ZQuest Classic Coverage Report


Directory: src/
File: src/gui/jwin.cpp
Date: 2024-05-02 03:25:59
Exec Total Coverage
Lines: 192 5650 3.4%
Functions: 16 148 10.8%
Branches: 249 4374 5.7%

Line Branch Exec Source
1 #include <ctype.h>
2 #include <cstring>
3 #include "base/zapp.h"
4 #include "base/zc_alleg.h"
5 #include <allegro/internal/aintern.h>
6 #include "gui/jwin.h"
7 #include "gui/editbox.h"
8 #include <iostream>
9 #include <sstream>
10 #include "base/zsys.h"
11 #include <stdio.h>
12 #include "base/util.h"
13 #include "pal.h"
14 #include "gui/tabpanel.h"
15 #include "gui/text_field.h"
16 #include "dialog/info.h"
17 #include "drawing.h"
18 using namespace util;
19 using std::string;
20 using std::istringstream;
21
22 void update_hw_screen(bool force);
23 extern int32_t zq_screen_w, zq_screen_h;
24 extern int32_t joystick_index;
25 int CheckerCol1 = 7, CheckerCol2 = 8;
26
27 extern bool is_editor();
28
29 int32_t abc_patternmatch = 1;
30
31 char abc_keypresses[1024] = {0};
32 void wipe_abc_keypresses() { memset(abc_keypresses, 0, 1024); }
33
34 /* these are provided for external use */
35 int32_t jwin_colors[jcMAX] =
36 {
37 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
38 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
39 };
40
41 int32_t scheme[jcMAX] =
42 {
43 0xC0C0C0,0xF0F0F0,0xD0D0D0,0x808080,0x404040,0x000000,
44 0x000080,0x00F0F0,0xFFFFFF,0xFFFFFF,0x000000,0x000080,0xFFFFFF
45 };
46
47 int32_t jwin_pal[jcMAX] = {0};
48
49 // A pointer to this variable is used to identify the DIALOG belonging to
50 // the DialogRunner. It isn't used for anything else.
51 char newGuiMarker;
52
53 int32_t new_gui_event(DIALOG* d, guiEvent event)
54 {
55 for(int32_t i = 0; true; --d, ++i)
56 {
57 if(d->dp3 == &newGuiMarker)
58 {
59 d->d1 = i;
60 return d->proc(MSG_GUI_EVENT, d, event);
61 }
62 }
63
64 return -1;
65 }
66
67 void close_new_gui_dlg(DIALOG* d);
68
69 int32_t bound(int32_t x,int32_t low,int32_t high)
70 {
71 if(x<low) x=low;
72
73 if(x>high) x=high;
74
75 return x;
76 }
77 /*
78 float bound(float x,float low,float high)
79 {
80 if(x<low) x=low;
81 if(x>high) x=high;
82 return x;
83 }
84 */
85
86 int32_t get_selected_tab(TABPANEL* panel)
87 {
88 for(int32_t i=0; panel[i].text; ++i)
89 {
90 if((panel[i].flags&D_SELECTED)!=0)
91 return i;
92 }
93 return -1;
94 }
95
96 /* jwin_set_colors:
97 * Loads a set of colors in 0xRRGGBB or 256-color-indexed format
98 * into the current color scheme using the appropriate color depth
99 * conversions.
100 */
101 176 void jwin_set_colors(int32_t *colors)
102 {
103 176 int32_t i = 0;
104
105
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if(bitmap_color_depth(screen) == 8)
106 {
107 // use color indices
108
2/2
✓ Branch 0 taken 176 times.
✓ Branch 1 taken 3696 times.
3872 for(; i<jcMAX; i++)
109 3696 scheme[i] = colors[i];
110 176 }
111 else
112 {
113 // 0xRRGGBB format
114 for(; i<jcMAX; i++)
115 scheme[i] = makecol(colors[i]>>16, (colors[i]>>8)&0xFF, colors[i]&0xFF);
116 }
117 176 }
118
119 /* jwin_set_dialog_color:
120 * Sets the foreground and background colors of all the objects in a dialog.
121 *
122 * Needs work!
123 */
124 void jwin_set_dialog_color(DIALOG *dialog)
125 {
126 int32_t c;
127
128 for(c=0; dialog[c].proc; c++)
129 {
130 dialog[c].fg = scheme[jcMEDDARK];
131 dialog[c].bg = scheme[jcBOX];
132 }
133 }
134
135 /* jwin_draw_frame:
136 * Draws a frame using the specified style.
137 */
138 void jwin_draw_frame(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t style)
139 {
140 optional<int> c1,c2,c3,c4;
141
142 switch(style)
143 {
144 case FR_INVIS:
145 return;
146 case FR_BOX:
147 c1 = jcLIGHT;
148 c2 = jcMEDLT;
149 c3 = jcMEDDARK;
150 c4 = jcDARK;
151 break;
152
153 case FR_INV:
154 c1 = jcDARK;
155 c2 = jcMEDDARK;
156 c3 = jcMEDLT;
157 c4 = jcLIGHT;
158 break;
159
160 case FR_DEEP:
161 c1 = jcMEDDARK;
162 c2 = jcDARK;
163 c3 = jcMEDLT;
164 c4 = jcLIGHT;
165 break;
166
167 case FR_DARK:
168 c1 = jcDARK;
169 c2 = jcMEDDARK;
170 c3 = jcMEDDARK;
171 c4 = jcDARK;
172 break;
173
174 case FR_ETCHED:
175 c1 = jcMEDDARK;
176 c2 = jcLIGHT;
177 c3 = jcMEDDARK;
178 c4 = jcLIGHT;
179 break;
180
181 case FR_MEDDARK:
182 c1 = jcMEDDARK;
183 c2 = jcBOX;
184 c3 = jcBOX;
185 c4 = jcMEDDARK;
186 break;
187
188 case FR_MENU:
189 c1 = jcLIGHT;
190 c4 = jcMEDDARK;
191 break;
192 case FR_MENU_INV:
193 c1 = jcMEDDARK;
194 c2 = jcMEDDARK;
195 c3 = jcLIGHT;
196 c4 = jcLIGHT;
197 break;
198
199 case FR_WIN:
200 default:
201 c1 = jcMEDLT;
202 c2 = jcLIGHT;
203 c3 = jcMEDDARK;
204 c4 = jcDARK;
205 break;
206 }
207
208 if(c1) c1 = scheme[*c1];
209 if(c2) c2 = scheme[*c2];
210 if(c3) c3 = scheme[*c3];
211 if(c4) c4 = scheme[*c4];
212 switch (style)
213 {
214 case FR_RED:
215 c1 = 0xE4;
216 c2 = 0xEC;
217 c3 = 0xE4;
218 c4 = 0xEC;
219 break;
220 case FR_GREEN:
221 c1 = 0xE2;
222 c2 = 0xEA;
223 c3 = 0xE2;
224 c4 = 0xEA;
225 break;
226 }
227 if(c1)
228 {
229 _allegro_hline(dest, vbound(x,0,dest->w-1), vbound(y,0,dest->h-1) , vbound(x+w-2, 0,dest->w-1), *c1);
230 _allegro_vline(dest, vbound(x,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-2, 0, dest->h-1), *c1);
231 }
232 if(c2)
233 {
234 _allegro_hline(dest, vbound(x+1,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(x+w-3,0,dest->w-1), *c2);
235 _allegro_vline(dest, vbound(x+1,0,dest->w-1), vbound(y+2,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c2);
236 }
237 if(c3)
238 {
239 _allegro_hline(dest, vbound(x+1,0,dest->w-1), vbound(y+h-2,0,dest->h-1), vbound(x+w-2,0,dest->w-1), *c3);
240 _allegro_vline(dest, vbound(x+w-2,0,dest->w-1), vbound(y+1,0,dest->h-1), vbound(y+h-3,0,dest->h-1), *c3);
241 }
242 if(c4)
243 {
244
245 _allegro_hline(dest, vbound(x,0,dest->w-1), vbound(y+h-1,0,dest->h-1), vbound(x+w-1,0, dest->w-1), *c4);
246 _allegro_vline(dest, vbound(x+w-1,0,dest->w-1), vbound(y,0,dest->h-1), vbound(y+h-2,0,dest->h-1), *c4);
247 }
248 }
249 void jwin_draw_frag_frame(BITMAP* dest, int x1, int y1, int w, int h, int fw, int fh, int style)
250 {
251 int c1,c2,c3,c4;
252
253 switch(style)
254 {
255 case FR_BOX:
256 c1 = jcLIGHT;
257 c2 = jcMEDLT;
258 c3 = jcMEDDARK;
259 c4 = jcDARK;
260 break;
261
262 case FR_INV:
263 c1 = jcDARK;
264 c2 = jcMEDDARK;
265 c3 = jcMEDLT;
266 c4 = jcLIGHT;
267 break;
268
269 case FR_DEEP:
270 c1 = jcMEDDARK;
271 c2 = jcDARK;
272 c3 = jcMEDLT;
273 c4 = jcLIGHT;
274 break;
275
276 case FR_DARK:
277 c1 = jcDARK;
278 c2 = jcMEDDARK;
279 c3 = jcMEDDARK;
280 c4 = jcDARK;
281 break;
282
283 case FR_ETCHED:
284 c1 = jcMEDDARK;
285 c2 = jcLIGHT;
286 c3 = jcMEDDARK;
287 c4 = jcLIGHT;
288 break;
289
290 case FR_MEDDARK:
291 c1 = jcMEDDARK;
292 c2 = jcBOX;
293 c3 = jcBOX;
294 c4 = jcMEDDARK;
295 break;
296
297 case FR_WIN:
298 default:
299 c1 = jcMEDLT;
300 c2 = jcLIGHT;
301 c3 = jcMEDDARK;
302 c4 = jcDARK;
303 break;
304 }
305
306 int xc = x1+fw-1;
307 int yc = y1+fh-1;
308 int x2 = x1+w-1;
309 int y2 = y1+h-1;
310
311 rectfill(dest, x1, y1, x2, yc, vc(0));
312 rectfill(dest, x1, yc, xc, y2, vc(0));
313
314 _allegro_hline(dest, x1-2, y1-2, x2+2, scheme[c1]);
315 _allegro_hline(dest, x1-1, y1-1, x2+1, scheme[c2]);
316
317 _allegro_vline(dest, x1-2, y1-2, y2+2, scheme[c1]);
318 _allegro_vline(dest, x1-1, y1-1, y2+1, scheme[c2]);
319
320 _allegro_hline(dest, x1-2, y2+2, xc+2, scheme[c3]);
321 _allegro_hline(dest, x1-1, y2+1, xc+1, scheme[c4]);
322
323 _allegro_vline(dest, x2+2, y1-2, yc+2, scheme[c3]);
324 _allegro_vline(dest, x2+1, y1-1, yc+1, scheme[c4]);
325
326 _allegro_hline(dest, xc+2, yc+2, x2+2, scheme[c3]);
327 _allegro_hline(dest, xc+1, yc+1, x2+1, scheme[c4]);
328
329 _allegro_vline(dest, xc+2, yc+2, y2+2, scheme[c3]);
330 _allegro_vline(dest, xc+1, yc+1, y2+1, scheme[c4]);
331 }
332 void jwin_draw_minimap_frame(BITMAP *dest,int x,int y,int w,int h,int scrsz,int style)
333 {
334 jwin_draw_frag_frame(dest,x,y,w,h,scrsz*8,scrsz*8,style);
335 }
336
337 /* jwin_draw_win:
338 * Draws a window -- a box with a frame.
339 */
340 void jwin_draw_win(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t frame)
341 {
342 rectfill(dest,zc_max(x,0),zc_max(y,0),zc_min(x+w-1, dest->w-1),zc_min(y+h-1, dest->h-1),scheme[jcBOX]);
343 jwin_draw_frame(dest, x, y, w, h, frame);
344 }
345
346 /* jwin_draw_button:
347 * Helper function for buttons.
348 * Draws a box with a frame that depends on "state":
349 * 0: normal border (slightly different than window border)
350 * 1: inverted border
351 * 2: dark border
352 * 3: medium dark border
353 */
354 void jwin_draw_button(BITMAP *dest,int32_t x,int32_t y,int32_t w,int32_t h,int32_t state,int32_t type)
355 {
356 int32_t frame = FR_BOX;
357
358 if(type==1)
359 {
360 frame=FR_WIN;
361 }
362
363 switch(state)
364 {
365 case 1:
366 frame = FR_INV;
367 break;
368
369 case 2:
370 frame = FR_DARK;
371 break;
372
373 case 3:
374 frame = FR_MEDDARK;
375 break;
376 }
377
378 jwin_draw_win(dest, x, y, w, h, frame);
379 }
380
381 /* mix_value:
382 * Returns a mix of the values c1 and c2 with pos==0 being c1,
383 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
384 */
385 int32_t mix_value(int32_t c1,int32_t c2,int32_t pos,int32_t max)
386 {
387 if(max<=0)
388 return c1;
389
390 return (c2 - c1) * pos / max + c1;
391 }
392
393 /* mix_color:
394 * Returns a mix of the colors c1 and c2 with pos==0 being c1,
395 * pos==max being c2, pos==max/2 being half way between c1 and c2, etc.
396 *
397 static int32_t mix_color(int32_t c1,int32_t c2,int32_t pos,int32_t max)
398 {
399 int32_t c;
400
401 if(bitmap_color_depth(screen) == 8)
402 c = mix_value(c1, c2, pos, max);
403 else
404 {
405 int32_t r = mix_value(getr(c1), getr(c2), pos, max);
406 int32_t g = mix_value(getg(c1), getg(c2), pos, max);
407 int32_t b = mix_value(getb(c1), getb(c2), pos, max);
408 c = makecol(r,g,b);
409 }
410
411 return c;
412 }
413 */
414
415 char *shorten_string(char *dest, char const* src, FONT *usefont, int32_t maxchars, int32_t maxwidth)
416 {
417 strncpy(dest,src,maxchars);
418 dest[maxchars-1]='\0';
419 int32_t len=(int32_t)strlen(dest);
420 int32_t width=text_length(usefont, dest);
421 dest[len]=0;
422
423 while(width>maxwidth && len>4)
424 {
425 dest[len-4] = '.';
426 dest[len-3] = '.';
427 dest[len-2] = '.';
428 dest[len-1] = 0;
429 len--;
430 width=text_length(usefont, dest);
431 }
432
433 return dest;
434 }
435
436 void jwin_draw_titlebar(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, bool draw_button, bool helpbtn)
437 {
438 char buf[512];
439 int32_t len = (int32_t)strlen(str);
440 int32_t length = text_length(font,str);
441 int32_t height = text_height(font);
442
443 int32_t tx = x + 2;
444 int32_t ty = y + (h-height)/2;
445 PALETTE temp_pal;
446 get_palette(temp_pal);
447 dither_rect(dest, &temp_pal, x, y, x+w-1, y+h-1,
448 makecol15(temp_pal[scheme[jcTITLEL]].r*255/63,
449 temp_pal[scheme[jcTITLEL]].g*255/63,
450 temp_pal[scheme[jcTITLEL]].b*255/63),
451 makecol15(temp_pal[scheme[jcTITLER]].r*255/63,
452 temp_pal[scheme[jcTITLER]].g*255/63,
453 temp_pal[scheme[jcTITLER]].b*255/63),
454 scheme[jcTITLEL], scheme[jcTITLER]);
455
456
457 if(len>509)
458 len=509;
459
460 strncpy(buf,str,len);
461 buf[len]=0;
462
463 // this part needs work
464
465 if(length>w-20)
466 {
467 while(length>w-20 && len>1)
468 {
469 buf[len-4] = '.';
470 buf[len-3] = '.';
471 buf[len-2] = '.';
472 buf[len-1] = 0;
473 len--;
474 length = text_length(font,buf);
475 }
476 }
477
478 textout_ex(dest,font,buf,tx,ty,scheme[jcTITLEFG],-1);
479
480 if(draw_button)
481 {
482 draw_x_button(dest, x + w - 18, y+2, 0);
483 }
484
485 if(helpbtn)
486 {
487 draw_question_button(dest, x + w - (draw_button ? 36 : 18), y+2, 0);
488 }
489
490 }
491
492 void draw_question_button(BITMAP* dest, int32_t x, int32_t y, int32_t state)
493 {
494 int32_t c = scheme[jcBOXFG];
495
496 jwin_draw_button(dest,x,y,16,14,state,0);
497 x += 4 + (state?1:0);
498 y += 3 + (state?1:0);
499
500 line(dest, x+2, y+0, x+5, y+0, c);
501 line(dest, x+1, y+1, x+2, y+1, c);
502 line(dest, x+5, y+1, x+6, y+1, c);
503 line(dest, x+4, y+2, x+5, y+2, c);
504 line(dest, x+3, y+3, x+4, y+3, c);
505 line(dest, x+3, y+4, x+4, y+4, c);
506 line(dest, x+3, y+6, x+4, y+6, c);
507 line(dest, x+3, y+7, x+4, y+7, c);
508 }
509
510 void draw_x_button(BITMAP *dest, int32_t x, int32_t y, int32_t state)
511 {
512 int32_t c = scheme[jcBOXFG];
513
514 jwin_draw_button(dest,x,y,16,14,state,0);
515 x += 4 + (state?1:0);
516 y += 3 + (state?1:0);
517
518 line(dest,x, y, x+6,y+6,c);
519 line(dest,x+1,y, x+7,y+6,c);
520 line(dest,x, y+6,x+6,y, c);
521 line(dest,x+1,y+6,x+7,y, c);
522 }
523
524 void draw_arrow(BITMAP *dest, int c, int x, int y, int h, bool up, bool center)
525 {
526 if(!center)
527 x += h-1;
528 for(int i = 0; i<h; i++)
529 _allegro_hline(dest, x-(up?i:h-i-1), y+i, x+(up?i:h-i-1), c);
530 }
531 void draw_arrow_horz(BITMAP *dest, int c, int x, int y, int w, bool left, bool center)
532 {
533 if(!center)
534 y += w-1;
535 for(int i = 0; i<w; i++)
536 _allegro_vline(dest, x+i, y-(left?i:w-i-1), y+(left?i:w-i-1), c);
537 }
538 void draw_arrow_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
539 {
540 int32_t c = scheme[jcDARK];
541 int32_t ah = zc_min(h/3, 5);
542 int32_t i = 0;
543
544 jwin_draw_button(dest,x,y,w,h,state,1);
545 x += w/2 - (state?0:1);
546 y += (h-ah)/2 + (state?1:0);
547
548 for(; i<ah; i++)
549 {
550 _allegro_hline(dest, x-(up?i:ah-i-1), y+i, x+(up?i:ah-i-1), c);
551 }
552 }
553
554 void draw_arrow_button_horiz(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int32_t up, int32_t state)
555 {
556 int32_t c = scheme[jcDARK];
557 int32_t aw = zc_min(w/3, 5);
558 int32_t i = 0;
559
560 jwin_draw_button(dest,x,y,w,h,state,1);
561 y += h/2 - (state?0:1);
562 x += (w-aw)/2 + (state?1:0);
563
564 for(; i<aw; i++)
565 {
566 _allegro_vline(dest, x+i,y-(up?i:aw-i-1), y+(up?i:aw-i-1), c);
567 }
568 }
569
570 int32_t mouse_in_rect(int32_t x,int32_t y,int32_t w,int32_t h)
571 {
572 return ((gui_mouse_x() >= x) && (gui_mouse_y() >= y) &&
573 (gui_mouse_x() < x + w) && (gui_mouse_y() < y + h));
574 }
575
576 static int32_t jwin_do_x_button(BITMAP *dest, int32_t x, int32_t y)
577 {
578 int32_t down=0, last_draw = 0;
579
580 while(gui_mouse_b())
581 {
582 down = mouse_in_rect(x,y,16,14);
583
584 if(down!=last_draw)
585 {
586 draw_x_button(dest,x,y,down);
587 last_draw = down;
588 }
589
590 /* let other objects continue to animate */
591 broadcast_dialog_message(MSG_IDLE, 0);
592 rest(1);
593 }
594
595 if(down)
596 {
597 draw_x_button(dest,x,y,0);
598 }
599
600 return down;
601 }
602
603 /* dotted_rect:
604 * Draws a dotted rectangle, for showing an object has the input focus.
605 */
606 void dotted_rect(BITMAP *dest, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
607 {
608 int32_t x = ((x1+y1) & 1) ? 1 : 0;
609 int32_t c;
610
611 //acquire the bitmap ourselves, because locking a surface within each call is *SLOW AS BALLS* -DD
612 acquire_bitmap(dest);
613
614 for(c=x1; c<=x2; c++)
615 {
616 putpixel(dest, c, y1, (((c+y1) & 1) == x) ? fg : bg);
617 putpixel(dest, c, y2, (((c+y2) & 1) == x) ? fg : bg);
618 }
619
620 for(c=y1+1; c<y2; c++)
621 {
622 putpixel(dest, x1, c, (((c+x1) & 1) == x) ? fg : bg);
623 putpixel(dest, x2, c, (((c+x2) & 1) == x) ? fg : bg);
624 }
625
626 release_bitmap(dest);
627
628 }
629
630 static void _dotted_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t fg, int32_t bg)
631 {
632 dotted_rect(screen, x1, y1, x2, y2, fg, bg);
633 }
634
635 static bool no_hline = false;
636 /* gui_textout_ln:
637 * Wrapper function for drawing text to the screen, which interprets the
638 * & character as an underbar for displaying keyboard shortcuts. Returns
639 * the width of the output string in pixels.
640 *
641 * Handles '\n' characters.
642 */
643 3 int32_t gui_textout_ln(BITMAP *bmp, FONT *f, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
644 {
645 char tmp[1024];
646 3 int32_t c = 0;
647 int32_t len;
648 3 int32_t pix_len = 0;
649 3 int32_t max_len = 0;
650 int32_t hline_pos;
651 3 int32_t xx = x;
652 3 bool is_scr = bmp == screen;
653
654
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
10 while(s[c])
655 {
656 7 len = 0;
657 7 hline_pos = -1;
658
659
4/4
✓ Branch 0 taken 366 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 366 times.
369 for(; (s[c]) && (len<(int32_t)(sizeof(tmp)-1)); c++)
660 {
661
2/2
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 4 times.
366 if(s[c] == '\n')
662 {
663 4 c++;
664 4 break;
665 }
666
2/4
✓ Branch 0 taken 362 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 362 times.
✗ Branch 3 not taken.
362 else if(!no_hline && s[c] == '&')
667 {
668 if(s[c+1] != '&')
669 hline_pos = len;
670 else
671 {
672 tmp[len++] = '&';
673 c++;
674 }
675 }
676 else
677 362 tmp[len++] = s[c];
678 362 }
679
680 7 tmp[len] = 0;
681 7 pix_len = text_length(f, tmp);
682
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (pix_len > max_len) max_len = pix_len;
683 7 x = xx;
684
685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(pos==1) //center
686 {
687 x -= pix_len / 2;
688 }
689
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 else if(pos==2) //right
690 {
691 x -= pix_len;
692 }
693
694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if(bmp)
695 {
696 7 textout_ex(bmp, f, tmp, x, y, color,bg);
697
698
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if(hline_pos >= 0)
699 {
700 int32_t i;
701 i = tmp[hline_pos];
702 tmp[hline_pos] = 0;
703 hline_pos = text_length(f, tmp);
704 tmp[0] = i;
705 tmp[1] = 0;
706 i = text_length(f, tmp);
707 _allegro_hline(bmp, x+hline_pos, y+text_height(f)-gui_font_baseline, x+hline_pos+i-1, color);
708 }
709 7 }
710
711 7 y += text_height(f);
712 }
713 3 return max_len;
714 }
715
716 3 int32_t gui_textout_ln(BITMAP *bmp, unsigned const char *s, int32_t x, int32_t y, int32_t color, int32_t bg, int32_t pos)
717 {
718 3 return gui_textout_ln(bmp, font, s, x, y, color, bg, pos);
719 }
720
721 int32_t gui_text_width(FONT *f, const char *s)
722 {
723 return gui_textout_ln(NULL, f, (uint8_t*)s, 0, 0, 0, 0, 0);
724 }
725
726 3 int32_t count_newline(uint8_t *s)
727 {
728 3 int32_t cnt = 0;
729
2/2
✓ Branch 0 taken 366 times.
✓ Branch 1 taken 3 times.
369 for(int32_t q = 0; s[q] != 0; ++q)
730 {
731
2/2
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 4 times.
366 if(s[q] == '\n') ++cnt;
732 366 }
733 3 return cnt;
734 }
735
736 3 int32_t gui_textheight(FONT* f, uint8_t *s)
737 {
738 3 return text_height(f) * (count_newline(s) + 1);
739 }
740
741 3 int32_t gui_textheight(uint8_t* s)
742 {
743 3 return gui_textheight(font, s);
744 }
745
746 /*******************************/
747 /***** Misc Dialog Procs *****/
748 /*******************************/
749
750 /* typedef for the listbox callback functions */
751 typedef char *(*getfuncptr)(int32_t, int32_t *);
752
753 /* event handler that closes a dialog */
754 int32_t close_dlg()
755 {
756 return D_CLOSE;
757 }
758
759 int32_t jwin_frame_proc(int32_t msg, DIALOG *d, int32_t c)
760 {
761 //these are here to bypass compiler warnings about unused arguments
762 c=c;
763
764 if(msg == MSG_DRAW)
765 {
766 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
767 }
768
769 return D_O_K;
770 }
771
772 int32_t jwin_guitest_proc(int32_t msg, DIALOG *d, int32_t c)
773 {
774 //these are here to bypass compiler warnings about unused arguments
775 c=c;
776
777 if(msg == MSG_DRAW)
778 {
779 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, d->d1);
780 }
781
782 return D_O_K;
783 }
784
785 /* jwin_win_proc:
786 * Draws a box with a frame. Use dp for a title string. If dp is NULL,
787 * it won't draw a title bar. If the D_EXIT flag is set, it will also
788 * draw an "X" button on the title bar that can be used to close the
789 * dialog.
790 * If d->dp3 is non-null, it will be read as a help text string, and
791 * a ? button will be drawn, that upon clicking will display the helptext.
792 */
793 int32_t jwin_win_proc(int32_t msg, DIALOG *d, int32_t c)
794 {
795 //these are here to bypass compiler warnings about unused arguments
796 c=c;
797
798 rest(1);
799 static bool skipredraw = false;
800
801 switch(msg)
802 {
803 case MSG_DRAW:
804 if(skipredraw)
805 {
806 skipredraw = false;
807 break;
808 }
809 jwin_draw_win(screen, d->x, d->y, d->w, d->h, FR_WIN);
810
811 if(d->dp)
812 {
813 FONT *oldfont = font;
814
815 if(d->dp2)
816 {
817 font = (FONT*)d->dp2;
818 }
819
820 jwin_draw_titlebar(screen, d->x+3, d->y+3, d->w-6, 18, (char*)d->dp, d->flags & D_EXIT, d->dp3!=NULL);
821 font = oldfont;
822 }
823 break;
824
825 case MSG_WANTFOCUS:
826 if(gui_mouse_b())
827 return D_WANTFOCUS|D_REDRAW;
828 else return D_O_K;
829 case MSG_GOTFOCUS:
830 case MSG_LOSTFOCUS:
831 skipredraw = true;
832 return D_O_K;
833
834 case MSG_CLICK:
835 {
836 if((d->flags & D_EXIT) && mouse_in_rect(d->x+d->w-21, d->y+5, 16, 14))
837 {
838 if(jwin_do_x_button(screen, d->x+d->w-21, d->y+5))
839 {
840 GUI_EVENT(d, geCLOSE);
841 return D_CLOSE;
842 }
843 }
844 if(char const* helpstr = (char const*)d->dp3)
845 {
846 if(mouse_in_rect(d->x+d->w-((d->flags&D_EXIT)?39:21), d->y+5, 16, 14))
847 {
848 broadcast_dialog_message(MSG_DRAW,0);
849 InfoDialog("Info", helpstr).show();
850 }
851 }
852 }
853 break;
854 }
855
856 return D_O_K;
857 }
858
859 /* jwin_text_proc:
860 * Simple dialog procedure: draws the text string which is pointed to by dp.
861 *
862 * Handles '\n' characters.
863 */
864 3 int32_t jwin_text_proc(int32_t msg, DIALOG *d, int32_t)
865 {
866 ASSERT(d);
867
3/6
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
868
869
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 switch(msg)
870 {
871 case MSG_START:
872 {
873 3 FONT *oldfont = font;
874
875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(d->dp2)
876 {
877 3 font = (FONT*)d->dp2;
878 3 }
879
880 3 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
881 3 d->h=gui_textheight((uint8_t *)d->dp);
882
883 3 font = oldfont;
884 3 break;
885 }
886 case MSG_DRAW:
887 {
888 FONT *oldfont = font;
889
890 if(d->dp2)
891 {
892 font = (FONT*)d->dp2;
893 }
894
895 if(d->flags & D_DISABLED)
896 {
897 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
898 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 0);
899 }
900 else
901 {
902 d->w=gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 0);
903 }
904
905 font = oldfont;
906 break;
907 }
908 }
909
910 3 return D_O_K;
911 }
912
913 int32_t jwin_ctext_proc(int32_t msg, DIALOG *d, int32_t)
914 {
915 ASSERT(d);
916 static BITMAP *dummy=create_bitmap_ex(8, 320, 240);
917
918 switch(msg)
919 {
920 case MSG_START:
921 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 0);
922 break;
923
924 case MSG_DRAW:
925 FONT *oldfont = font;
926
927 if(d->dp2)
928 {
929 font = (FONT*)d->dp2;
930 }
931
932 if(d->flags & D_DISABLED)
933 {
934 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 1);
935 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 1);
936 }
937 else
938 {
939 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 1);
940 }
941
942 font = oldfont;
943 break;
944 }
945
946 return D_O_K;
947 }
948
949 int32_t jwin_rtext_proc(int32_t msg, DIALOG *d, int32_t)
950 {
951 ASSERT(d);
952 static BITMAP *dummy=create_bitmap_ex(8, 1, 1);
953
954 switch(msg)
955 {
956 case MSG_START:
957 d->w=gui_textout_ln(dummy, (uint8_t *)d->dp, 0, 0, scheme[jcMEDDARK], -1, 2);
958 break;
959
960 case MSG_DRAW:
961 FONT *oldfont = font;
962
963 if(d->dp2)
964 {
965 font = (FONT*)d->dp2;
966 }
967
968 if(d->flags & D_DISABLED)
969 {
970 gui_textout_ln(screen, (uint8_t*)d->dp, d->x+1, d->y+1, scheme[jcLIGHT], scheme[jcBOX], 2);
971 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcDISABLED_FG], -1, 2);
972 }
973 else
974 {
975 gui_textout_ln(screen, (uint8_t*)d->dp, d->x, d->y, scheme[jcBOXFG], scheme[jcBOX], 2);
976 }
977
978 font = oldfont;
979 break;
980 }
981
982 return D_O_K;
983 }
984
985 int32_t d_ctext2_proc(int32_t msg, DIALOG *d, int32_t c)
986 {
987 auto ret = d_ctext_proc(msg, d, c);
988 return ret;
989 }
990
991 int32_t new_text_proc(int32_t msg, DIALOG *d, int32_t c)
992 {
993 BITMAP* oldscreen = screen;
994 if(msg==MSG_DRAW)
995 {
996 if(d->flags & D_HIDDEN) return D_O_K;
997 screen = create_bitmap_ex(8,oldscreen->w,oldscreen->h);
998 clear_bitmap(screen);
999 set_clip_rect(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1);
1000 }
1001 int32_t ret = D_O_K;
1002 int32_t w = d->w, h = d->h, x = d->x, y = d->y;
1003 if(d->d2) no_hline = true;
1004 switch(d->d1)
1005 {
1006 case 0:
1007 ret = jwin_text_proc(msg, d, c);
1008 break;
1009 case 1:
1010 d->x += d->w/2;
1011 ret = jwin_ctext_proc(msg, d, c);
1012 break;
1013 case 2:
1014 d->x += d->w - 1;
1015 ret = jwin_rtext_proc(msg, d, c);
1016 break;
1017 }
1018 no_hline = false;
1019 d->w = w;
1020 d->h = h;
1021 d->x = x;
1022 d->y = y;
1023 if(msg==MSG_DRAW)
1024 {
1025 masked_blit(screen, oldscreen, d->x, d->y, d->x, d->y, d->w, d->h);
1026 destroy_bitmap(screen);
1027 screen = oldscreen;
1028 }
1029 if(msg==MSG_WANTFOCUS && gui_mouse_b())
1030 ret |= D_WANTFOCUS|D_REDRAW;
1031 return ret;
1032 }
1033
1034 /* draw_text_button:
1035 * Helper for jwin_button_proc.
1036 */
1037 void jwin_draw_text_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, const char *str, int32_t flags, bool show_dotted_rect)
1038 {
1039 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1040
1041 if(flags & D_SELECTED)
1042 {
1043 jwin_draw_button(dest, x, y, w, h, 2, 0);
1044 flags &= ~D_DISABLED;
1045 }
1046 else if(!(flags & D_GOTFOCUS))
1047 jwin_draw_button(dest, x, y, w, h, 0, 0);
1048 else
1049 {
1050 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1051 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1052 }
1053
1054 bool drawstring = true;
1055 if(str[1]==0 && byte(str[0]) >= 0x80)
1056 {
1057 drawstring = false;
1058 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1059 int aw = w/4, ah = h/4;
1060 int woff = (aw/2)+1, hoff = (ah/2)+1;
1061 int x1 = x+w/2, x2 = x+(w-aw)/2;
1062 int y1 = y+(h-aw)/2, y2 = y+h/2;
1063 switch(byte(str[0]))
1064 {
1065 case 0x88:
1066 draw_arrow(dest, col, x1, y1, ah, true, true);
1067 break;
1068 case 0x89:
1069 draw_arrow(dest, col, x1, y1, ah, false, true);
1070 break;
1071 case 0x8A:
1072 draw_arrow_horz(dest, col, x2, y2, aw, true, true);
1073 break;
1074 case 0x8B:
1075 draw_arrow_horz(dest, col, x2, y2, aw, false, true);
1076 break;
1077 case 0x98:
1078 draw_arrow(dest, col, x1, y1-hoff, ah, false, true);
1079 draw_arrow(dest, col, x1, y1+hoff, ah, true, true);
1080 break;
1081 case 0x99:
1082 draw_arrow(dest, col, x1, y1-hoff, ah, true, true);
1083 draw_arrow(dest, col, x1, y1+hoff, ah, false, true);
1084 break;
1085 case 0x9A:
1086 draw_arrow_horz(dest, col, x2-woff, y2, aw, false, true);
1087 draw_arrow_horz(dest, col, x2+woff, y2, aw, true, true);
1088 break;
1089 case 0x9B:
1090 draw_arrow_horz(dest, col, x2-woff, y2, aw, true, true);
1091 draw_arrow_horz(dest, col, x2+woff, y2, aw, false, true);
1092 break;
1093 default: drawstring = true;
1094 }
1095 }
1096 if(drawstring)
1097 {
1098 if(!(flags & D_DISABLED))
1099 gui_textout_ex(dest, str, x+w/2+g, y+(h-text_height(font))/2+g, scheme[jcBOXFG], -1, TRUE);
1100 else
1101 {
1102 gui_textout_ex(dest, str, x+w/2+1,y+(h-text_height(font))/2+1, scheme[jcLIGHT], -1, TRUE);
1103 gui_textout_ex(dest, str, x+w/2, y+(h-text_height(font))/2, scheme[jcDISABLED_FG], -1, TRUE);
1104 }
1105 }
1106
1107 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1108 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1109 }
1110
1111 int icon_proportion(int icon,int s1,int s2)
1112 {
1113 int sz = round(sqrt(zc_min(s1,s2))*1.25);
1114 switch(icon)
1115 {
1116 case BTNICON_STOPSQUARE:
1117 sz += 4;
1118 break;
1119 case BTNICON_PLUS:
1120 case BTNICON_MINUS:
1121 sz += 4;
1122 break;
1123 }
1124 return sz;
1125 }
1126 void jwin_draw_icon_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, int icon, int32_t flags, bool show_dotted_rect)
1127 {
1128 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1129
1130 if(flags & D_SELECTED)
1131 jwin_draw_button(dest, x, y, w, h, 2, 0);
1132 else if(!(flags & D_GOTFOCUS))
1133 jwin_draw_button(dest, x, y, w, h, 0, 0);
1134 else
1135 {
1136 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1137 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1138 }
1139
1140 int col = jwin_pal[(flags & D_DISABLED) ? jcLIGHT : jcBOXFG];
1141 jwin_draw_icon(dest,x+w/2,y+h/2,col,icon,icon_proportion(icon,w,h),true);
1142
1143 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1144 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1145 }
1146 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int asz, bool center)
1147 {
1148 jwin_draw_icon(dest,x,y,col,icon,asz,asz,center);
1149 }
1150 void jwin_draw_icon(BITMAP *dest, int x, int y, int col, int icon, int aw, int ah, bool center)
1151 {
1152 int w2 = aw, h2 = ah;
1153 int sz = zc_min(aw,ah);
1154 switch(icon)
1155 {
1156 case BTNICON_ARROW_LEFT2:
1157 case BTNICON_ARROW_RIGHT2:
1158 aw *= 2;
1159 ah = aw*2-1;
1160 break;
1161 case BTNICON_ARROW_LEFT3:
1162 case BTNICON_ARROW_RIGHT3:
1163 aw *= 3;
1164 ah = aw*2-1;
1165 break;
1166 case BTNICON_ARROW_UP:
1167 case BTNICON_ARROW_DOWN:
1168 case BTNICON_CONTRACT_VERT:
1169 case BTNICON_EXPAND_VERT:
1170 aw = ah*2-1;
1171 break;
1172 case BTNICON_ARROW_LEFT:
1173 case BTNICON_ARROW_RIGHT:
1174 case BTNICON_CONTRACT_HORZ:
1175 case BTNICON_EXPAND_HORZ:
1176 ah = aw*2-1;
1177 break;
1178 case BTNICON_STOPSQUARE:
1179 aw = ah = sz;
1180 break;
1181 case BTNICON_PLUS:
1182 if(!(sz%2)) ++sz;
1183 aw = ah = w2 = h2 = sz;
1184 w2 /= 3;
1185 h2 /= 3;
1186 if(!(h2%2)) ++h2;
1187 if(!(w2%2)) ++w2;
1188 break;
1189 case BTNICON_MINUS:
1190 if(!(sz%2)) ++sz;
1191 aw = ah = w2 = h2 = sz;
1192 h2 /= 3;
1193 if(!(h2%2)) ++h2;
1194 break;
1195 }
1196 int woff = (aw/2)+1, hoff = (ah/2)+1;
1197 int cx = center ? (x-aw/2) : x,
1198 cy = center ? (y-ah/2) : y;
1199 switch(icon)
1200 {
1201 case BTNICON_ARROW_UP:
1202 draw_arrow(dest, col, x, cy, ah, true, center);
1203 break;
1204 case BTNICON_ARROW_DOWN:
1205 draw_arrow(dest, col, x, cy, ah, false, center);
1206 break;
1207 case BTNICON_ARROW_LEFT:
1208 draw_arrow_horz(dest, col, cx, y, aw, true, center);
1209 break;
1210 case BTNICON_ARROW_RIGHT:
1211 draw_arrow_horz(dest, col, cx, y, aw, false, center);
1212 break;
1213 case BTNICON_CONTRACT_VERT:
1214 draw_arrow(dest, col, x, cy-hoff, ah, false, center);
1215 draw_arrow(dest, col, x, cy+hoff, ah, true, center);
1216 break;
1217 case BTNICON_EXPAND_VERT:
1218 draw_arrow(dest, col, x, cy-hoff, ah, true, center);
1219 draw_arrow(dest, col, x, cy+hoff, ah, false, center);
1220 break;
1221 case BTNICON_CONTRACT_HORZ:
1222 draw_arrow_horz(dest, col, cx-woff, y, aw, false, center);
1223 draw_arrow_horz(dest, col, cx+woff, y, aw, true, center);
1224 break;
1225 case BTNICON_EXPAND_HORZ:
1226 draw_arrow_horz(dest, col, cx-woff, y, aw, true, center);
1227 draw_arrow_horz(dest, col, cx+woff, y, aw, false, center);
1228 break;
1229 case BTNICON_ARROW_LEFT2:
1230 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1231 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1232 break;
1233 case BTNICON_ARROW_LEFT3:
1234 draw_arrow_horz(dest, col, cx, y, w2, true, center);
1235 draw_arrow_horz(dest, col, cx+w2, y, w2, true, center);
1236 draw_arrow_horz(dest, col, cx+w2*2, y, w2, true, center);
1237 break;
1238 case BTNICON_ARROW_RIGHT2:
1239 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1240 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1241 break;
1242 case BTNICON_ARROW_RIGHT3:
1243 draw_arrow_horz(dest, col, cx, y, w2, false, center);
1244 draw_arrow_horz(dest, col, cx+w2, y, w2, false, center);
1245 draw_arrow_horz(dest, col, cx+w2*2, y, w2, false, center);
1246 break;
1247 case BTNICON_STOPSQUARE:
1248 rectfill(dest, cx, cy, cx+aw-1, cy+ah-1, col);
1249 break;
1250 case BTNICON_MINUS:
1251 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1252 break;
1253 case BTNICON_PLUS:
1254 rectfill(dest, cx, cy+(ah/2)-(h2/2), cx+aw-1, cy+(ah/2)+(h2/2), col);
1255 rectfill(dest, cx+(aw/2)-(w2/2), cy, cx+(aw/2)+(w2/2), cy+ah-1, col);
1256 break;
1257 }
1258 }
1259 /* draw_graphics_button:
1260 * Helper for jwin_button_proc.
1261 */
1262 void jwin_draw_graphics_button(BITMAP *dest, int32_t x, int32_t y, int32_t w, int32_t h, BITMAP *bmp, BITMAP *bmp2, int32_t flags, bool show_dotted_rect, bool overlay)
1263 {
1264 int32_t g = (flags & D_SELECTED) ? 1 : 0;
1265
1266 if(flags & D_SELECTED)
1267 jwin_draw_button(dest, x, y, w, h, 2, 0);
1268 else if(!(flags & D_GOTFOCUS))
1269 jwin_draw_button(dest, x, y, w, h, 0, 0);
1270 else
1271 {
1272 rect(dest, x, y, x+w-1, y+h-1, scheme[jcDARK]);
1273 jwin_draw_button(dest, x+1, y+1, w-2, h-2, 0, 0);
1274 }
1275
1276 if(!(flags & D_DISABLED))
1277 {
1278 // gui_textout_ex(dest, str, x+w/2+g, y+h/2-text_height(font)/2+g, scheme[jcBOXFG], -1, TRUE);
1279 if(bmp!=NULL)
1280 {
1281 if(overlay)
1282 {
1283 masked_blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1284 }
1285 else
1286 {
1287 blit(bmp, dest, 0, 0, x+w/2-bmp->w/2+g, y+h/2-bmp->h/2+g, bmp->h, bmp->w);
1288 }
1289 }
1290 }
1291 else
1292 {
1293 // gui_textout_ex(dest, str, x+w/2+1,y+h/2-text_height(font)/2+1, scheme[jcLIGHT], -1, TRUE);
1294 // gui_textout_ex(dest, str, x+w/2, y+h/2-text_height(font)/2, scheme[jcMEDDARK], -1, TRUE);
1295 if(bmp2!=NULL)
1296 {
1297 if(overlay)
1298 {
1299 masked_blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1300 }
1301 else
1302 {
1303 blit(bmp2, dest, 0, 0, x+w/2-bmp2->w/2+g, y+h/2-bmp2->h/2+g, bmp2->h, bmp2->w);
1304 }
1305 }
1306 }
1307
1308 if(show_dotted_rect&&(flags & D_GOTFOCUS))
1309 dotted_rect(dest, x+4, y+4, x+w-5, y+h-5, scheme[jcDARK], scheme[jcBOX]);
1310 }
1311
1312 /* jwin_button_proc:
1313 * A button object (the dp field points to the text string). This object
1314 * can be selected by clicking on it with the mouse or by pressing its
1315 * keyboard shortcut. If the D_EXIT flag is set, selecting it will close
1316 * the dialog, otherwise it will toggle on and off.
1317 */
1318 int32_t jwin_button_proc(int32_t msg, DIALOG *d, int32_t)
1319 {
1320 int32_t down=0;
1321 int32_t selected=(d->flags&D_SELECTED)?1:0;
1322 int32_t disabled=(d->flags&D_DISABLED)?1:0;
1323 int32_t last_draw;
1324
1325 switch(msg)
1326 {
1327 case MSG_DRAW:
1328 {
1329 FONT *oldfont = font;
1330
1331 if(d->dp2)
1332 {
1333 font = (FONT*)d->dp2;
1334 }
1335
1336 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, (char*)d->dp, d->flags, true);
1337 font = oldfont;
1338 }
1339 break;
1340
1341 case MSG_WANTFOCUS:
1342 return D_WANTFOCUS;
1343
1344 case MSG_KEY:
1345 if(disabled) break;
1346 /* close dialog? */
1347 if(d->flags & D_EXIT)
1348 {
1349 return D_CLOSE;
1350 }
1351 if(d->d2 == 1) //Insta-button
1352 {
1353 GUI_EVENT(d, geCLICK);
1354 break;
1355 }
1356 /* or just toggle */
1357 d->flags ^= D_SELECTED;
1358 GUI_EVENT(d, geCLICK);
1359 object_message(d, MSG_DRAW, 0);
1360 break;
1361
1362 case MSG_CLICK:
1363 {
1364 if(disabled) break;
1365 if(d->d2 == 1) //Insta-button
1366 {
1367 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1368 {
1369 GUI_EVENT(d, geCLICK);
1370 if(d->flags & D_EXIT)
1371 return D_CLOSE;
1372 }
1373 }
1374 else
1375 {
1376 last_draw = 0;
1377
1378 /* track the mouse until it is released */
1379 while(gui_mouse_b())
1380 {
1381 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1382
1383 /* redraw? */
1384 bool should_redraw = false;
1385 if(last_draw != down)
1386 {
1387 if(down != selected)
1388 d->flags |= D_SELECTED;
1389 else
1390 d->flags &= ~D_SELECTED;
1391
1392 object_message(d, MSG_DRAW, 0);
1393 last_draw = down;
1394 should_redraw = true;
1395 }
1396
1397 /* let other objects continue to animate */
1398 int r = broadcast_dialog_message(MSG_IDLE, 0);
1399 if (r & D_REDRAWME) should_redraw = true;
1400
1401 if (should_redraw)
1402 {
1403 update_hw_screen();
1404 }
1405 }
1406
1407 /* redraw in normal state */
1408 if(down)
1409 {
1410 GUI_EVENT(d, geCLICK);
1411 if(d->flags&D_EXIT)
1412 {
1413 d->flags &= ~D_SELECTED;
1414 object_message(d, MSG_DRAW, 0);
1415 }
1416 }
1417
1418 /* should we close the dialog? */
1419 if(down && (d->flags & D_EXIT))
1420 return D_CLOSE;
1421 }
1422 }
1423 break;
1424 }
1425 return D_O_K;
1426 }
1427 int32_t jwin_iconbutton_proc(int32_t msg, DIALOG *d, int32_t)
1428 {
1429 int32_t down=0;
1430 int32_t selected=(d->flags&D_SELECTED)?1:0;
1431 int32_t last_draw;
1432
1433 switch(msg)
1434 {
1435 case MSG_DRAW:
1436 {
1437 jwin_draw_icon_button(screen, d->x, d->y, d->w, d->h, d->d1, d->flags, true);
1438 }
1439 break;
1440
1441 case MSG_WANTFOCUS:
1442 return D_WANTFOCUS;
1443
1444 case MSG_KEY:
1445 /* close dialog? */
1446 if(d->flags & D_EXIT)
1447 {
1448 return D_CLOSE;
1449 }
1450 if(d->d2 == 1) //Insta-button
1451 {
1452 GUI_EVENT(d, geCLICK);
1453 break;
1454 }
1455 /* or just toggle */
1456 d->flags ^= D_SELECTED;
1457 GUI_EVENT(d, geCLICK);
1458 object_message(d, MSG_DRAW, 0);
1459 break;
1460
1461 case MSG_CLICK:
1462 {
1463 if(d->d2 == 1) //Insta-button
1464 {
1465 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1466 {
1467 GUI_EVENT(d, geCLICK);
1468 if(d->flags & D_EXIT)
1469 return D_CLOSE;
1470 }
1471 }
1472 else
1473 {
1474 last_draw = 0;
1475
1476 /* track the mouse until it is released */
1477 while(gui_mouse_b())
1478 {
1479 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1480
1481 /* redraw? */
1482 bool should_redraw = false;
1483 if(last_draw != down)
1484 {
1485 if(down != selected)
1486 d->flags |= D_SELECTED;
1487 else
1488 d->flags &= ~D_SELECTED;
1489
1490 object_message(d, MSG_DRAW, 0);
1491 last_draw = down;
1492 should_redraw = true;
1493 }
1494
1495 /* let other objects continue to animate */
1496 int r = broadcast_dialog_message(MSG_IDLE, 0);
1497 if (r & D_REDRAWME) should_redraw = true;
1498
1499 if (should_redraw)
1500 {
1501 update_hw_screen();
1502 }
1503 }
1504
1505 /* redraw in normal state */
1506 if(down)
1507 {
1508 GUI_EVENT(d, geCLICK);
1509 if(d->flags&D_EXIT)
1510 {
1511 d->flags &= ~D_SELECTED;
1512 object_message(d, MSG_DRAW, 0);
1513 }
1514 }
1515
1516 /* should we close the dialog? */
1517 if(down && (d->flags & D_EXIT))
1518 return D_CLOSE;
1519 }
1520 }
1521 break;
1522 }
1523 return D_O_K;
1524 }
1525 int32_t jwin_infobtn_proc(int32_t msg, DIALOG *d, int32_t)
1526 {
1527 int32_t down=0;
1528 int32_t selected=(d->flags&D_SELECTED)?1:0;
1529 int32_t last_draw;
1530 std::string* str = (std::string*)d->dp;
1531 bool dis = (d->flags & D_DISABLED) || !str || !((*str)[0]) || str->find_first_not_of(" \t")==std::string::npos;
1532 int flags = d->flags | (dis?D_DISABLED:0);
1533 bool show = false;
1534 switch(msg)
1535 {
1536 case MSG_DRAW:
1537 {
1538 FONT *oldfont = font;
1539
1540 if(d->dp2)
1541 font = (FONT*)d->dp2;
1542
1543 jwin_draw_text_button(screen, d->x, d->y, d->w, d->h, "?", flags, true);
1544 font = oldfont;
1545 }
1546 break;
1547
1548 case MSG_WANTFOCUS:
1549 if(dis) break;
1550 return D_WANTFOCUS;
1551
1552 case MSG_KEY:
1553 if(dis) break;
1554 show = true;
1555 break;
1556
1557 case MSG_CLICK:
1558 {
1559 if(dis) break;
1560 if(d->d2 == 1) //Insta-button
1561 {
1562 if(mouse_in_rect(d->x, d->y, d->w, d->h))
1563 {
1564 show = true;
1565 break;
1566 }
1567 }
1568 else
1569 {
1570 last_draw = 0;
1571
1572 /* track the mouse until it is released */
1573 while(gui_mouse_b())
1574 {
1575 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1576
1577 /* redraw? */
1578 bool should_redraw = false;
1579 if(last_draw != down)
1580 {
1581 if(down != selected)
1582 d->flags |= D_SELECTED;
1583 else
1584 d->flags &= ~D_SELECTED;
1585
1586 object_message(d, MSG_DRAW, 0);
1587 last_draw = down;
1588 should_redraw = true;
1589 }
1590
1591 /* let other objects continue to animate */
1592 int r = broadcast_dialog_message(MSG_IDLE, 0);
1593 if (r & D_REDRAWME) should_redraw = true;
1594
1595 if (should_redraw)
1596 {
1597 update_hw_screen();
1598 }
1599 }
1600
1601 /* redraw in normal state */
1602 if(down)
1603 show = true;
1604 }
1605 }
1606 break;
1607 }
1608 if(show)
1609 {
1610 d->flags &= ~D_SELECTED;
1611 object_message(d, MSG_DRAW, 0);
1612 InfoDialog("Info",*str).show();
1613 GUI_EVENT(d, geCLICK);
1614 }
1615 return D_O_K;
1616 }
1617
1618 /* jwin_func_button_proc:
1619 * A button that runs a void() function when clicked.
1620 * dp: Button text
1621 * dp2: Function to run
1622 */
1623 int32_t jwin_func_button_proc(int32_t msg, DIALOG *d, int32_t c)
1624 {
1625 int32_t down=0;
1626 int32_t selected=(d->flags&D_SELECTED)?1:0;
1627 int32_t last_draw;
1628
1629 if(msg==MSG_CLICK || msg==MSG_KEY)
1630 {
1631 last_draw = 0;
1632
1633 /* track the mouse until it is released */
1634 while(gui_mouse_b())
1635 {
1636 down = mouse_in_rect(d->x, d->y, d->w, d->h);
1637
1638 /* redraw? */
1639 bool should_redraw = false;
1640 if(last_draw != down)
1641 {
1642 if(down != selected)
1643 d->flags |= D_SELECTED;
1644 else
1645 d->flags &= ~D_SELECTED;
1646
1647 object_message(d, MSG_DRAW, 0);
1648 last_draw = down;
1649 should_redraw = true;
1650 }
1651
1652 /* let other objects continue to animate */
1653 int r = broadcast_dialog_message(MSG_IDLE, 0);
1654 if (r & D_REDRAWME) should_redraw = true;
1655
1656 if (should_redraw)
1657 {
1658 update_hw_screen();
1659 }
1660 }
1661
1662 /* redraw in normal state */
1663 if(down)
1664 {
1665 if(d->flags&D_EXIT)
1666 {
1667 d->flags &= ~D_SELECTED;
1668 object_message(d, MSG_DRAW, 0);
1669 }
1670 }
1671
1672 /* pop up and call the function */
1673 if(down)
1674 {
1675 d->flags &= ~D_SELECTED;
1676 object_message(d, MSG_DRAW, 0);
1677 typedef void (*funcType)(void);
1678 funcType func=reinterpret_cast<funcType>(d->dp3);
1679 func();
1680 }
1681
1682 return D_O_K;
1683 }
1684
1685 return jwin_button_proc(msg, d, c);
1686 }
1687
1688 /*(int32_t x = atoi(d->dp);
1689 if ( x > 256 )
1690 d->dp = (char*)"255";
1691 elseif (x < 0 ) d->dp = (char*)"0";
1692 */
1693
1694 int32_t jwin_vedit_proc(int32_t msg, DIALOG *d, int32_t c)
1695 {
1696 if(d->flags & D_HIDDEN)
1697 {
1698 switch(msg)
1699 {
1700 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
1701 return D_O_K;
1702 }
1703 }
1704 if(d->h < 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
1705 return jwin_edit_proc(msg, d, c);
1706 static char nullbuf[2];
1707 sprintf(nullbuf, " ");
1708 int32_t f, l, p, w, x, y, fg, bg;
1709 int32_t lastSpace = -1;
1710 char *s;
1711 char buf[2] = {0,0};
1712
1713 if(d->dp==NULL)
1714 {
1715 d->dp=(void *)nullbuf;
1716 }
1717
1718 s = (char*)d->dp;
1719 l = (int32_t)strlen(s);
1720
1721 int32_t cursor_start = d->d2 & 0x0000FFFF;
1722 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
1723 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
1724 if (cursor_start == 0xFFFF)
1725 cursor_start = -1;
1726 if (cursor_end == 0xFFFF)
1727 cursor_end = -1;
1728
1729 if(cursor_start > l)
1730 cursor_start = l;
1731 if(cursor_end > l)
1732 cursor_end = l;
1733 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
1734 auto high_cursor = zc_max(cursor_start,cursor_end);
1735 bool multiselect = cursor_end > -1;
1736
1737 FONT *oldfont = font;
1738 if(d->dp2)
1739 font = (FONT*)d->dp2;
1740
1741 auto* char_length = font->vtable->char_length;
1742 std::vector<size_t> lines;
1743 x = 0;
1744
1745 y = d->y + 2;
1746 size_t ind = 0;
1747 int32_t yinc = text_height(font)+2;
1748 int32_t maxy = y;
1749 size_t maxlines = 1;
1750 while(maxy+yinc < d->y+d->h-3)
1751 {
1752 maxy += yinc;
1753 ++maxlines;
1754 }
1755 size_t half_width = (maxlines-1)/2;
1756 size_t line_scroll = 0;
1757 size_t focused_line = size_t(-1);
1758 size_t focused_line2 = size_t(-1);
1759 switch(msg)
1760 {
1761 //Only these messages need these calculations, so save processing.
1762 case MSG_DRAW:
1763 case MSG_CLICK:
1764 case MSG_CHAR:
1765 {
1766 for(auto q = 0; q <= l; ++q)
1767 {
1768 char c = s[q] ? s[q] : ' ';
1769 x += char_length(font, c);
1770 if(x > d->w - 6)
1771 {
1772 // Line's too long, break
1773 if(lastSpace >= 0)
1774 {
1775 q = lastSpace+1;
1776 lines.push_back(q);
1777 lastSpace = -1;
1778 }
1779 else
1780 {
1781 lines.push_back(q);
1782 }
1783 x = 0;
1784 --q; //counteract increment
1785 }
1786 else if(c == ' ')
1787 lastSpace = q;
1788 }
1789 if(lines.empty() || lines.back() != l+1)
1790 lines.push_back(l+1);
1791 for(size_t line = 0; line < lines.size(); ++line)
1792 {
1793 if(size_t(multiselect ? cursor_end : cursor_start) < lines[line]) //should ALWAYS execute once
1794 {
1795 focused_line = line;
1796 break;
1797 }
1798 }
1799 if(!multiselect)
1800 {
1801 focused_line2 = -1;
1802 }
1803 else for(size_t line = 0; line < lines.size(); ++line)
1804 {
1805 if(size_t(cursor_start) < lines[line]) //should ALWAYS execute once
1806 {
1807 focused_line2 = line;
1808 break;
1809 }
1810 }
1811 if (focused_line >= lines.size())
1812 focused_line = lines.size() - 1;
1813 if (focused_line2 >= lines.size())
1814 focused_line2 = lines.size() - 1;
1815 if(maxlines >= lines.size() || focused_line <= half_width)
1816 line_scroll = 0;
1817 else if(lines.size()-maxlines+half_width < focused_line)
1818 line_scroll = lines.size()-maxlines+half_width-1;
1819 else
1820 line_scroll = focused_line - half_width;
1821 }
1822 }
1823 font = oldfont; //in case of early return, need to reset here
1824 static bool dclick = false;
1825 switch(msg)
1826 {
1827 case MSG_START:
1828 dclick = false;
1829 cursor_start = (int32_t)strlen((char*)d->dp);
1830 cursor_end = -1;
1831 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1832 break;
1833
1834 case MSG_DRAW:
1835 {
1836 if(d->dp2)
1837 font = (FONT*)d->dp2;
1838 if(d->flags & D_DISABLED)
1839 {
1840 fg = scheme[jcDISABLED_FG];
1841 bg = scheme[jcDISABLED_BG];
1842 }
1843 else if(d->flags & D_READONLY)
1844 {
1845 fg = scheme[jcALT_TEXTFG];
1846 bg = scheme[jcALT_TEXTBG];
1847 }
1848 else
1849 {
1850 fg = scheme[jcTEXTFG];
1851 bg = scheme[jcTEXTBG];
1852 }
1853
1854 //Fill the BG
1855 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg);
1856
1857 //Now the text
1858 size_t m = zc_min(line_scroll + maxlines, lines.size());
1859 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
1860 for(size_t line = line_scroll; line < m; ++line, y+=yinc)
1861 {
1862 x = 3;
1863 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1864 {
1865 char c = s[ind] ? s[ind] : ' ';
1866 w = char_length(font, c);
1867 bool focused = multiselect
1868 ? (ind >= low_cursor && ind <= high_cursor)
1869 : (ind == cursor_start);
1870 f = (focused && (d->flags & D_GOTFOCUS));
1871 buf[0] = c;
1872 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
1873 x += w;
1874 }
1875 }
1876
1877 font = oldfont;
1878 break;
1879 }
1880
1881 case MSG_DCLICK:
1882 if ((gui_mouse_b() & 2) != 0)
1883 break;
1884 if (d->flags & (D_DISABLED | D_READONLY))
1885 break;
1886 dclick = true;
1887 break;
1888 case MSG_CLICK:
1889 {
1890 if(d->flags & (D_DISABLED|D_READONLY))
1891 break;
1892 if(d->dp2)
1893 font = (FONT*)d->dp2;
1894
1895 bool found = false;
1896 for(size_t line = line_scroll; line < lines.size() && line < (line_scroll + maxlines); ++line, y+=yinc)
1897 {
1898 if(gui_mouse_y() >= y+yinc)
1899 continue;
1900 x = d->x+3;
1901 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
1902 {
1903 x += char_length(font, s[ind]);
1904 if(x >= gui_mouse_x())
1905 {
1906 if(key_shifts&KB_SHIFT_FLAG)
1907 cursor_end = ind;
1908 else
1909 {
1910 cursor_start = ind;
1911 cursor_end = -1;
1912 if (dclick)
1913 cursor_end = cursor_start;
1914 }
1915 found = true;
1916 break;
1917 }
1918 }
1919 break;
1920 }
1921 if(!found)
1922 {
1923 if(key_shifts&KB_SHIFT_FLAG)
1924 cursor_end = l;
1925 else
1926 {
1927 cursor_start = l;
1928 cursor_end = -1;
1929 if (dclick)
1930 cursor_end = cursor_start;
1931 }
1932 }
1933
1934 if (dclick)
1935 {
1936 while (cursor_start > 0 && cursor_start < l)
1937 {
1938 if (s[cursor_start] == ' ')
1939 {
1940 if (cursor_start <= cursor_end)
1941 ++cursor_start;
1942 else
1943 --cursor_start;
1944 break;
1945 }
1946 if (cursor_start <= cursor_end)
1947 --cursor_start;
1948 else
1949 ++cursor_start;
1950 }
1951 while (cursor_end > 0 && cursor_end < l)
1952 {
1953 if (s[cursor_end] == ' ')
1954 {
1955 if (cursor_end >= cursor_start)
1956 --cursor_end;
1957 else
1958 ++cursor_end;
1959 break;
1960 }
1961 if (cursor_end >= cursor_start)
1962 ++cursor_end;
1963 else
1964 --cursor_end;
1965 }
1966 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1967 d->flags |= D_DIRTY;
1968 }
1969 else
1970 {
1971 if (cursor_end == cursor_start) cursor_end = -1;
1972 else d->flags |= D_DIRTY;
1973 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
1974 }
1975
1976 object_message(d, MSG_DRAW, 0);
1977 font = oldfont;
1978 dclick = false;
1979 break;
1980 }
1981
1982 case MSG_WANTFOCUS:
1983 case MSG_LOSTFOCUS:
1984 case MSG_KEY:
1985 if(d->flags & (D_DISABLED|D_READONLY))
1986 break;
1987 return D_WANTFOCUS;
1988
1989 case MSG_CHAR:
1990 {
1991 if(d->flags & (D_DISABLED|D_READONLY))
1992 break;
1993 bool shifted = key_shifts & KB_SHIFT_FLAG;
1994 bool ctrl = key_shifts & KB_CTRL_FLAG;
1995 bool change_cursor = true;
1996 int32_t scursor = cursor_start, ecursor = cursor_end;
1997 char upper_c = c>>8;
1998 char lower_c = c&255;
1999 if(shifted)
2000 {
2001 if(ecursor < 0)
2002 {
2003 ecursor = scursor;
2004 focused_line2 = focused_line;
2005 }
2006 }
2007 if(upper_c == KEY_LEFT)
2008 {
2009 if(shifted)
2010 {
2011 if(ecursor>0)
2012 --ecursor;
2013 }
2014 else
2015 {
2016 ecursor = -1;
2017 if(scursor > 0)
2018 --scursor;
2019 }
2020 }
2021 else if(upper_c == KEY_RIGHT)
2022 {
2023 if(shifted)
2024 {
2025 if(ecursor < l)
2026 ++ecursor;
2027 }
2028 else
2029 {
2030 ecursor = -1;
2031 if(scursor < l)
2032 ++scursor;
2033 }
2034 }
2035 else if(upper_c == KEY_UP || upper_c == KEY_DOWN)
2036 {
2037 if(shifted)
2038 {
2039 size_t line = focused_line2 + (upper_c == KEY_UP ? -1 : 1);
2040 if(!focused_line2 && upper_c == KEY_UP)
2041 ecursor = 0;
2042 else if(line >= lines.size())
2043 ecursor = l;
2044 else
2045 {
2046 if(d->dp2)
2047 font = (FONT*)d->dp2;
2048 x = d->x + 3;
2049 for(ind = focused_line2 ? lines[focused_line2-1] : 0; ind < lines[focused_line2]; ++ind)
2050 {
2051 w = char_length(font, s[ind]);
2052 if(ind < size_t(ecursor))
2053 x += w;
2054 else
2055 {
2056 x += w / 2;
2057 break;
2058 }
2059 }
2060
2061 int32_t tx = d->x+3;
2062 bool done = false;
2063 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2064 {
2065 tx += char_length(font, s[ind] ? s[ind] : ' ');
2066 if(tx < x)
2067 continue;
2068 ecursor = ind;
2069 done = true;
2070 break;
2071 }
2072 font = oldfont;
2073 if(!done)
2074 {
2075 ecursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2076 }
2077 }
2078 }
2079 else
2080 {
2081 ecursor = -1;
2082 if(multiselect)
2083 {
2084 focused_line = focused_line2;
2085 scursor = ecursor;
2086 }
2087 size_t line = focused_line + (upper_c == KEY_UP ? -1 : 1);
2088 if(!focused_line && upper_c == KEY_UP)
2089 scursor = 0;
2090 else if(line >= lines.size())
2091 scursor = l;
2092 else
2093 {
2094 if(d->dp2)
2095 font = (FONT*)d->dp2;
2096 x = d->x + 3;
2097 for(ind = focused_line ? lines[focused_line-1] : 0; ind < lines[focused_line]; ++ind)
2098 {
2099 w = char_length(font, s[ind]);
2100 if(ind < size_t(scursor))
2101 x += w;
2102 else
2103 {
2104 x += w / 2;
2105 break;
2106 }
2107 }
2108
2109 int32_t tx = d->x+3;
2110 bool done = false;
2111 for(ind = line ? lines[line-1] : 0; ind < lines[line]; ++ind)
2112 {
2113 tx += char_length(font, s[ind] ? s[ind] : ' ');
2114 if(tx < x)
2115 continue;
2116 scursor = ind;
2117 done = true;
2118 break;
2119 }
2120 font = oldfont;
2121 if(!done)
2122 {
2123 scursor = (upper_c == KEY_UP) ? 0 : lines[line]-1;
2124 }
2125 }
2126 }
2127 }
2128 else if(upper_c == KEY_HOME)
2129 {
2130 if(shifted)
2131 ecursor = 0;
2132 else
2133 {
2134 ecursor = -1;
2135 scursor = 0;
2136 }
2137 }
2138 else if(upper_c == KEY_END)
2139 {
2140 if(shifted)
2141 ecursor = l;
2142 else
2143 {
2144 ecursor = -1;
2145 scursor = l;
2146 }
2147 }
2148 else if(upper_c == KEY_DEL)
2149 {
2150 if(ctrl)
2151 {
2152 s[0] = 0;
2153 scursor = 0;
2154 ecursor = -1;
2155 GUI_EVENT(d, geCHANGE_VALUE);
2156 }
2157 else if(multiselect)
2158 {
2159 ecursor = -1;
2160 scursor = low_cursor;
2161 size_t ind = low_cursor, ind2 = high_cursor+1;
2162 while(s[ind2])
2163 s[ind++] = s[ind2++];
2164 while(s[ind])
2165 s[ind++] = 0;
2166 GUI_EVENT(d, geCHANGE_VALUE);
2167 }
2168 else if(scursor < l)
2169 {
2170 for(p=scursor; s[p]; p++)
2171 s[p] = s[p+1];
2172 GUI_EVENT(d, geCHANGE_VALUE);
2173 }
2174 }
2175 else if(upper_c == KEY_BACKSPACE)
2176 {
2177 if(ctrl)
2178 {
2179 s[0] = 0;
2180 scursor = 0;
2181 ecursor = -1;
2182 GUI_EVENT(d, geCHANGE_VALUE);
2183 }
2184 else if(multiselect)
2185 {
2186 ecursor = -1;
2187 scursor = low_cursor;
2188 size_t ind = low_cursor, ind2 = high_cursor+1;
2189 while(s[ind2])
2190 s[ind++] = s[ind2++];
2191 while(s[ind])
2192 s[ind++] = 0;
2193 GUI_EVENT(d, geCHANGE_VALUE);
2194 }
2195 else if(scursor > 0)
2196 {
2197 --scursor;
2198 for(p=scursor; s[p]; p++)
2199 s[p] = s[p+1];
2200 GUI_EVENT(d, geCHANGE_VALUE);
2201 }
2202 }
2203 else if(upper_c == KEY_ENTER)
2204 {
2205 change_cursor = false;
2206 GUI_EVENT(d, geENTER);
2207 if(d->flags & D_EXIT)
2208 {
2209 object_message(d, MSG_DRAW, 0);
2210 return D_CLOSE;
2211 }
2212 else
2213 return D_O_K;
2214 }
2215 else if(upper_c == KEY_TAB)
2216 {
2217 change_cursor = false;
2218 return D_O_K;
2219 }
2220 else if(ctrl && (lower_c=='c' || lower_c=='C'))
2221 {
2222 change_cursor = false;
2223 std::ostringstream oss;
2224 if(multiselect)
2225 {
2226 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2227 {
2228 if(s[ind])
2229 oss << s[ind];
2230 }
2231 }
2232 else
2233 {
2234 if(s[scursor])
2235 oss << s[scursor];
2236 }
2237 set_al_clipboard(oss.str());
2238 }
2239 else if(clipboard_has_text() && ctrl && (lower_c=='v' || lower_c=='V'))
2240 {
2241 std::string cb;
2242 if(get_al_clipboard(cb))
2243 {
2244 int ind = low_cursor, ind2 = high_cursor + 1;
2245 if (multiselect)
2246 {
2247 //Delete selected text
2248 ecursor = -1;
2249 scursor = low_cursor;
2250 while (s[ind2] && ind2 < l)
2251 s[ind++] = s[ind2++];
2252 while (s[ind])
2253 s[ind++] = 0;
2254 l = (int32_t)strlen(s);
2255 }
2256 //Move the text out of the way of the pasting
2257 int paste_len = cb.size();
2258 int paste_start = scursor;
2259 int paste_end = paste_start+paste_len;
2260 ind = strlen(s);
2261 ind2 = ind+paste_len;
2262 while(ind2 > d->d1)
2263 {
2264 --ind;
2265 --ind2;
2266 }
2267 size_t new_l = ind2;
2268 while(ind >= paste_start)
2269 {
2270 if(s[ind] || (ind&&s[ind-1]))
2271 {
2272 s[ind2] = s[ind];
2273 }
2274 --ind2; --ind;
2275 }
2276 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2277 {
2278 s[paste_start+q] = cb.at(q);
2279 }
2280 s[new_l] = 0;
2281 scursor = paste_start + paste_len;
2282 ecursor = -1;
2283 GUI_EVENT(d, geCHANGE_VALUE);
2284 }
2285 }
2286 else if(ctrl && (lower_c=='a' || lower_c=='A'))
2287 {
2288 cursor_start = 0;
2289 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2290 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2291 d->flags |= D_DIRTY;
2292 break;
2293 }
2294 else if(lower_c >= 32)
2295 {
2296 if(multiselect)
2297 {
2298 //Delete selected text
2299 ecursor = -1;
2300 scursor = low_cursor;
2301 size_t ind = low_cursor, ind2 = high_cursor+1;
2302 while(s[ind2] && ind2 < l)
2303 s[ind++] = s[ind2++];
2304 while(s[ind])
2305 s[ind++] = 0;
2306 l = (int32_t)strlen(s);
2307 //Type the character in its' place
2308 //(fallthrough)
2309 }
2310 if(l < d->d1)
2311 {
2312 ecursor = -1;
2313 s[l+1] = 0;
2314 size_t ind = l;
2315 while(ind >= scursor)
2316 {
2317 s[ind+1] = s[ind];
2318 if (!ind) break;
2319 --ind;
2320 }
2321
2322 s[scursor++] = lower_c;
2323
2324 GUI_EVENT(d, geCHANGE_VALUE);
2325 }
2326 }
2327 else
2328 return D_O_K;
2329
2330 if(change_cursor)
2331 {
2332 if (cursor_start != scursor)
2333 d->flags |= D_DIRTY;
2334
2335 cursor_end = ecursor; cursor_start = scursor;
2336 if (cursor_end == cursor_start) cursor_end = -1;
2337 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2338 }
2339
2340 /* if we changed something, better redraw... */
2341 object_message(d, MSG_DRAW, 0);
2342 return D_USED_CHAR;
2343 }
2344 }
2345
2346 return D_O_K;
2347 }
2348
2349 /* jwin_edit_proc:
2350 * An editable text object (the dp field points to the string). When it
2351 * has the input focus (obtained by clicking on it with the mouse), text
2352 * can be typed into this object. The d1 field specifies the maximum
2353 * number of characters that it will accept, and d2 is the text cursor
2354 * position within the string.
2355 */
2356 int32_t jwin_edit_proc(int32_t msg, DIALOG *d, int32_t c)
2357 {
2358 if(d->flags & D_HIDDEN)
2359 {
2360 switch(msg)
2361 {
2362 case MSG_CHAR: case MSG_UCHAR: case MSG_XCHAR: case MSG_DRAW: case MSG_CLICK: case MSG_DCLICK: case MSG_KEY: case MSG_WANTFOCUS:
2363 return D_O_K;
2364 }
2365 }
2366 if(d->h >= 2+((text_height(d->dp2 ? (FONT*)d->dp2 : font)+2)*2))
2367 return jwin_vedit_proc(msg, d, c);
2368 int32_t f, l, p, w, x, y, fg, bg, fg2 = -1, bg2 = -1, fg3, bg3;
2369 int32_t b;
2370 int32_t scroll;
2371 char *s;
2372 char buf[2];
2373 static char nullbuf[2];
2374 sprintf(nullbuf, " ");
2375
2376 if(d->dp==NULL)
2377 {
2378 d->dp=(void *)nullbuf;
2379 }
2380
2381 s = (char*)d->dp;
2382 l = (int32_t)strlen(s);
2383
2384 int32_t cursor_start = d->d2 & 0x0000FFFF;
2385 int32_t cursor_end = int32_t((d->d2 & 0xFFFF0000) >> 16);
2386 // This was previously doing bitshifts on -1. There wasn't enough space so I cannibalized 0xFFFF instead. -Moosh
2387 if (cursor_start == 0xFFFF)
2388 cursor_start = -1;
2389 if (cursor_end == 0xFFFF)
2390 cursor_end = -1;
2391
2392 if(cursor_start > l)
2393 cursor_start = l;
2394 if(cursor_end > l)
2395 cursor_end = l;
2396 auto low_cursor = cursor_start<0 ? cursor_end : (cursor_end<0 ? cursor_start : (zc_min(cursor_start, cursor_end)));
2397 auto high_cursor = zc_max(cursor_start,cursor_end);
2398
2399 /* calculate maximal number of displayable characters */
2400 b = x = 0;
2401
2402 if(cursor_start == l)
2403 {
2404 buf[0] = ' ';
2405 buf[1] = 0;
2406
2407 if(d->dp2)
2408 x = text_length((FONT*)d->dp2, buf);
2409 else
2410 x = text_length(font, buf);
2411 }
2412
2413 buf[1] = 0;
2414
2415 for(p=cursor_start; p>=0; p--)
2416 {
2417 buf[0] = s[p];
2418 b++;
2419
2420 if(d->dp2)
2421 x += text_length((FONT*)d->dp2, buf);
2422 else
2423 x += text_length(font, buf);
2424
2425 if(x > d->w-6)
2426 break;
2427 }
2428
2429 if(x <= d->w-6)
2430 {
2431 b = l;
2432 scroll = FALSE;
2433 }
2434 else
2435 {
2436 b--;
2437 scroll = TRUE;
2438 }
2439
2440 FONT *oldfont = font;
2441 static bool dclick = false;
2442 switch(msg)
2443 {
2444 case MSG_START:
2445 dclick = false;
2446 cursor_start = (int32_t)strlen((char*)d->dp);
2447 cursor_end = -1;
2448 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2449 break;
2450
2451 case MSG_DRAW:
2452 {
2453 if(d->dp2)
2454 {
2455 font = (FONT*)d->dp2;
2456 }
2457 if(d->flags & D_DISABLED)
2458 {
2459 fg2 = scheme[jcLIGHT];
2460 bg2 = scheme[jcDISABLED_BG];
2461 fg = scheme[jcDISABLED_FG];
2462 bg = -1;
2463 fg3 = fg;
2464 bg3 = bg2;
2465 }
2466 else if(d->flags & D_READONLY)
2467 {
2468 fg = scheme[jcALT_TEXTFG];
2469 bg = scheme[jcALT_TEXTBG];
2470 fg3 = fg;
2471 bg3 = bg;
2472 }
2473 else
2474 {
2475 fg = scheme[jcTEXTFG];
2476 bg = scheme[jcTEXTBG];
2477 fg3 = fg;
2478 bg3 = bg;
2479 }
2480
2481 x = 3;
2482 y = (d->h - text_height(font)) / 2 + d->y;
2483
2484 /* first fill in the edges */
2485
2486 rectfill(screen, d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, bg3);
2487
2488 _allegro_vline(screen, d->x+2, d->y+2, d->y+d->h-3, bg3);
2489
2490 /* now the text */
2491
2492 if(scroll)
2493 {
2494 p = cursor_start-b+1;
2495 b = cursor_start;
2496 }
2497 else
2498 p = 0;
2499 for(; p<=b; p++)
2500 {
2501 buf[0] = s[p] ? s[p] : ' ';
2502 w = text_length(font, buf);
2503
2504 if(x+w > d->w)
2505 break;
2506 bool focused = (cursor_end>-1)
2507 ? (p >= low_cursor && p <= high_cursor)
2508 : (p == cursor_start);
2509 f = fg2 < 0 && (focused && (d->flags & D_GOTFOCUS));
2510 if(fg2 > -1)
2511 {
2512 textout_ex(screen, font, buf, d->x+x+1, y+1, fg2, bg2);
2513 }
2514 textout_ex(screen, font, buf, d->x+x, y, f ? bg : fg,f ? fg : bg);
2515 x += w;
2516 }
2517
2518 if(x < d->w-2)
2519 rectfill(screen, d->x+x, y, d->x+d->w-3, y+text_height(font)-1, bg3);
2520
2521 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
2522 font = oldfont;
2523 break;
2524 }
2525
2526 case MSG_DCLICK:
2527 if ((gui_mouse_b() & 2) != 0)
2528 break;
2529 if (d->flags & (D_DISABLED | D_READONLY))
2530 break;
2531 dclick = true;
2532 break;
2533 case MSG_CLICK:
2534 {
2535 if(d->flags & (D_DISABLED|D_READONLY))
2536 break;
2537 x = d->x+3;
2538
2539 if(scroll)
2540 {
2541 p = cursor_start-b+1;
2542 b = cursor_start;
2543 }
2544 else
2545 p = 0;
2546
2547 for(; p<b; p++)
2548 {
2549 buf[0] = s[p];
2550 x += text_length((d->dp2) ? (FONT*)d->dp2 : font, buf);
2551
2552 if(x > gui_mouse_x())
2553 break;
2554 }
2555
2556 if(key_shifts&KB_SHIFT_FLAG)
2557 cursor_end = MID(0, p, l);
2558 else
2559 {
2560 cursor_end = -1;
2561 cursor_start = MID(0, p, l);
2562 if (dclick)
2563 cursor_end = cursor_start;
2564 }
2565
2566 if (dclick)
2567 {
2568 while (cursor_start > 0 && cursor_start < l)
2569 {
2570 if (s[cursor_start] == ' ')
2571 {
2572 if (cursor_start <= cursor_end)
2573 ++cursor_start;
2574 else
2575 --cursor_start;
2576 break;
2577 }
2578 if (cursor_start <= cursor_end)
2579 --cursor_start;
2580 else
2581 ++cursor_start;
2582 }
2583 while (cursor_end > 0 && cursor_end < l)
2584 {
2585 if (s[cursor_end] == ' ')
2586 {
2587 if (cursor_end >= cursor_start)
2588 --cursor_end;
2589 else
2590 ++cursor_end;
2591 break;
2592 }
2593 if (cursor_end >= cursor_start)
2594 ++cursor_end;
2595 else
2596 --cursor_end;
2597 }
2598 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2599 d->flags |= D_DIRTY;
2600 }
2601 else
2602 {
2603 if (cursor_end == cursor_start) cursor_end = -1;
2604 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2605 }
2606 d->flags |= D_DIRTY;
2607 dclick = false;
2608 break;
2609 }
2610
2611 case MSG_WANTFOCUS:
2612 case MSG_LOSTFOCUS:
2613 case MSG_KEY:
2614 if(d->flags & (D_DISABLED|D_READONLY))
2615 break;
2616 return D_WANTFOCUS;
2617
2618 case MSG_CHAR:
2619 {
2620 if(d->flags & (D_DISABLED|D_READONLY))
2621 break;
2622 bool shifted = key_shifts & KB_SHIFT_FLAG;
2623 bool ctrl = key_shifts & KB_CTRL_FLAG;
2624 bool change_cursor = true;
2625 bool change_value = false;
2626 int16_t scursor = cursor_start, ecursor = cursor_end;
2627 bool multiselect = cursor_end > -1;
2628 auto upper_c = c>>8;
2629 auto lower_c = c&0xFF;
2630 if(shifted)
2631 {
2632 if(ecursor < 0)
2633 ecursor = scursor;
2634 }
2635 if(upper_c == KEY_LEFT)
2636 {
2637 if(shifted)
2638 {
2639 if(ecursor>0)
2640 --ecursor;
2641 }
2642 else
2643 {
2644 ecursor = -1;
2645 if(scursor > 0)
2646 --scursor;
2647 }
2648 }
2649 else if(upper_c == KEY_RIGHT)
2650 {
2651 if(shifted)
2652 {
2653 if(ecursor < l)
2654 ++ecursor;
2655 }
2656 else
2657 {
2658 ecursor = -1;
2659 if(scursor < l)
2660 ++scursor;
2661 }
2662 }
2663 else if(upper_c == KEY_HOME)
2664 {
2665 if(shifted)
2666 ecursor = 0;
2667 else
2668 {
2669 ecursor = -1;
2670 scursor = 0;
2671 }
2672 }
2673 else if(upper_c == KEY_END)
2674 {
2675 if(shifted)
2676 ecursor = l;
2677 else
2678 {
2679 ecursor = -1;
2680 scursor = l;
2681 }
2682 }
2683 else if(upper_c == KEY_DEL)
2684 {
2685 if(ctrl)
2686 {
2687 s[0] = 0;
2688 scursor = 0;
2689 ecursor = -1;
2690 GUI_EVENT(d, geCHANGE_VALUE);
2691 change_value = true;
2692 }
2693 else if(multiselect)
2694 {
2695 ecursor = -1;
2696 scursor = low_cursor;
2697 size_t ind = low_cursor, ind2 = high_cursor+1;
2698 while(s[ind2])
2699 s[ind++] = s[ind2++];
2700 while(s[ind])
2701 s[ind++] = 0;
2702 GUI_EVENT(d, geCHANGE_VALUE);
2703 change_value = true;
2704 }
2705 else if(scursor < l)
2706 {
2707 for(p=scursor; s[p]; p++)
2708 s[p] = s[p+1];
2709 GUI_EVENT(d, geCHANGE_VALUE);
2710 change_value = true;
2711 }
2712 }
2713 else if(upper_c == KEY_BACKSPACE)
2714 {
2715 if(ctrl)
2716 {
2717 s[0] = 0;
2718 scursor = 0;
2719 ecursor = -1;
2720 GUI_EVENT(d, geCHANGE_VALUE);
2721 change_value = true;
2722 }
2723 else if(multiselect)
2724 {
2725 ecursor = -1;
2726 scursor = low_cursor;
2727 size_t ind = low_cursor, ind2 = high_cursor+1;
2728 while(s[ind2])
2729 s[ind++] = s[ind2++];
2730 while(s[ind])
2731 s[ind++] = 0;
2732 GUI_EVENT(d, geCHANGE_VALUE);
2733 change_value = true;
2734 }
2735 else if(scursor > 0)
2736 {
2737 --scursor;
2738 for(p=scursor; s[p]; p++)
2739 s[p] = s[p+1];
2740 GUI_EVENT(d, geCHANGE_VALUE);
2741 change_value = true;
2742 }
2743 }
2744 else if(upper_c == KEY_ENTER)
2745 {
2746 change_cursor = false;
2747 GUI_EVENT(d, geENTER);
2748 if(d->flags & D_EXIT)
2749 {
2750 object_message(d, MSG_DRAW, 0);
2751 return D_CLOSE;
2752 }
2753 else
2754 return D_O_K;
2755 }
2756 else if(upper_c == KEY_TAB)
2757 {
2758 change_cursor = false;
2759 return D_O_K;
2760 }
2761 else if(ctrl && (lower_c=='c' || lower_c=='C'))
2762 {
2763 change_cursor = false;
2764 std::ostringstream oss;
2765 if(multiselect)
2766 {
2767 for(size_t ind = low_cursor; ind <= high_cursor; ++ind)
2768 {
2769 if(s[ind])
2770 oss << s[ind];
2771 }
2772 }
2773 else
2774 {
2775 if(s[scursor])
2776 oss << s[scursor];
2777 }
2778 set_al_clipboard(oss.str());
2779 }
2780 else if(clipboard_has_text() && ctrl && (lower_c=='v' || lower_c=='V'))
2781 {
2782 std::string cb;
2783 if(get_al_clipboard(cb))
2784 {
2785 int ind = low_cursor, ind2 = high_cursor + 1;
2786 if (multiselect)
2787 {
2788 //Delete selected text
2789 ecursor = -1;
2790 scursor = low_cursor;
2791 while (s[ind2] && ind2 < l)
2792 s[ind++] = s[ind2++];
2793 while (s[ind])
2794 s[ind++] = 0;
2795 l = (int32_t)strlen(s);
2796 }
2797 //Move the text out of the way of the pasting
2798 int paste_len = cb.size();
2799 int paste_start = scursor;
2800 int paste_end = paste_start+paste_len;
2801 ind = strlen(s);
2802 ind2 = ind+paste_len;
2803 while(ind2 > d->d1)
2804 {
2805 --ind;
2806 --ind2;
2807 }
2808 size_t new_l = ind2;
2809 while(ind >= paste_start)
2810 {
2811 if(s[ind] || (ind&&s[ind-1]))
2812 {
2813 s[ind2] = s[ind];
2814 }
2815 --ind2; --ind;
2816 }
2817 for(auto q = 0; q < paste_len && paste_start+q < new_l; ++q)
2818 {
2819 s[paste_start+q] = cb.at(q);
2820 }
2821 s[new_l] = 0;
2822 scursor = paste_start + paste_len;
2823 ecursor = -1;
2824 GUI_EVENT(d, geCHANGE_VALUE);
2825 change_value = true;
2826 }
2827 }
2828 else if(ctrl && (lower_c=='a' || lower_c=='A'))
2829 {
2830 cursor_start = 0;
2831 cursor_end = (int16_t)strlen((char*)d->dp) - 1;
2832 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2833 d->flags |= D_DIRTY;
2834 break;
2835 }
2836 else if(lower_c >= 32)
2837 {
2838 if(multiselect)
2839 {
2840 //Delete selected text
2841 ecursor = -1;
2842 scursor = low_cursor;
2843 size_t ind = low_cursor, ind2 = high_cursor+1;
2844 while(s[ind2] && ind2 < l)
2845 s[ind++] = s[ind2++];
2846 while(s[ind])
2847 s[ind++] = 0;
2848 l = (int32_t)strlen(s);
2849 //Type the character in its' place
2850 //(fallthrough)
2851 }
2852 if(l < d->d1)
2853 {
2854 ecursor = -1;
2855 s[l+1] = 0;
2856 size_t ind = l;
2857 while(ind >= scursor)
2858 {
2859 s[ind+1] = s[ind];
2860 if (!ind) break;
2861 --ind;
2862 }
2863
2864 s[scursor++] = lower_c;
2865
2866 GUI_EVENT(d, geCHANGE_VALUE);
2867 change_value = true;
2868 }
2869 }
2870 else
2871 return D_O_K;
2872 if(change_cursor)
2873 {
2874 cursor_end = ecursor; cursor_start = scursor;
2875 if (cursor_end == cursor_start) cursor_end = -1;
2876 d->d2 = cursor_start | (((cursor_end == -1 ? 0xFFFF : cursor_end) & 0xFFFF) << 16);
2877 }
2878 /* if we changed something, better redraw... */
2879 // Note: this still redraws when not necessary.
2880 if (change_value || change_cursor)
2881 d->flags |= D_DIRTY;
2882 return D_USED_CHAR;
2883 }
2884 }
2885 return D_O_K;
2886 }
2887
2888 int32_t jwin_hexedit_proc_old(int32_t msg,DIALOG *d,int32_t c)
2889 {
2890 if(msg==MSG_CHAR)
2891 if(((isalpha(c&255) && !isxdigit(c&255))) || ispunct(c&255))
2892 return D_USED_CHAR;
2893
2894 return jwin_edit_proc(msg,d,isalpha(c&255)?c&0xDF:c);
2895 }
2896
2897 bool editproc_special_key(int32_t c)
2898 {
2899 switch(c>>8)
2900 {
2901 case KEY_LEFT: case KEY_RIGHT:
2902 case KEY_HOME: case KEY_END:
2903 case KEY_DEL: case KEY_BACKSPACE:
2904 case KEY_ENTER: case KEY_TAB:
2905 return true;
2906 }
2907 if(key_shifts & KB_CTRL_FLAG)
2908 switch(c&255)
2909 {
2910 case 'c': case 'C':
2911 return true;
2912 case 'v': case 'V':
2913 return clipboard_has_text();
2914 }
2915 return false;
2916 }
2917 bool editproc_combined_key(int32_t c)
2918 {
2919 if(key_shifts & KB_CTRL_FLAG)
2920 switch(c&255)
2921 {
2922 case 'c': case 'C':
2923 return true;
2924 case 'v': case 'V':
2925 return clipboard_has_text();
2926 }
2927 return false;
2928 }
2929 int32_t jwin_hexedit_proc(int32_t msg,DIALOG *d,int32_t c)
2930 {
2931 bool caps_paste = false;
2932 if(msg==MSG_CHAR)
2933 {
2934 if(key_shifts & KB_CTRL_FLAG)
2935 {
2936 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
2937 {
2938 std::string cb;
2939 if(get_al_clipboard(cb))
2940 {
2941 if(cb.find_first_not_of("-.0123456789ABCDEFabcdef") != std::string::npos)
2942 return D_USED_CHAR;
2943 if(cb.find_first_of("abcdef") != std::string::npos)
2944 caps_paste = true;
2945 }
2946 else return D_USED_CHAR;
2947 }
2948 }
2949 switch(c&255)
2950 {
2951 case '-': case '.':
2952 case '0': case '1': case '2': case '3': case '4':
2953 case '5': case '6': case '7': case '8': case '9':
2954 case 'A': case 'B': case 'C':
2955 case 'D': case 'E': case 'F':
2956 break;
2957 case 'a': case 'b': case 'c':
2958 case 'd': case 'e': case 'f':
2959 c = (c&~255)|toupper(c&255);
2960 break;
2961 default:
2962 if(!editproc_special_key(c))
2963 return D_O_K;
2964 else if(!editproc_combined_key(c))
2965 c&=~255;
2966 }
2967 }
2968
2969 auto ret = jwin_edit_proc(msg,d,c);
2970 if(caps_paste)
2971 {
2972 char* s = (char*)d->dp;
2973 caps_paste = false;
2974 for(auto q = strlen(s)-1; q >= 0; --q)
2975 {
2976 switch(s[q])
2977 {
2978 case 'a': case 'b': case 'c':
2979 case 'd': case 'e': case 'f':
2980 s[q] = toupper(s[q]);
2981 caps_paste = true;
2982 break;
2983 }
2984 }
2985 if(caps_paste)
2986 {
2987 jwin_edit_proc(MSG_DRAW,d,0);
2988 }
2989 }
2990 return ret;
2991 }
2992 int32_t jwin_numedit_proc(int32_t msg,DIALOG *d,int32_t c)
2993 {
2994 if(msg==MSG_CHAR)
2995 {
2996 if(key_shifts & KB_CTRL_FLAG)
2997 {
2998 if(clipboard_has_text() && ((c&255)=='v' || (c&255)=='V'))
2999 {
3000 std::string cb;
3001 if(get_al_clipboard(cb))
3002 {
3003 if(cb.find_first_not_of("-.0123456789") != std::string::npos)
3004 return D_USED_CHAR;
3005 }
3006 else return D_USED_CHAR;
3007 }
3008 }
3009 switch(c&255)
3010 {
3011 case '-': case '.':
3012 case '0': case '1': case '2': case '3': case '4':
3013 case '5': case '6': case '7': case '8': case '9':
3014 break;
3015 default:
3016 if(!editproc_special_key(c))
3017 return D_O_K;
3018 else if(!editproc_combined_key(c))
3019 c&=~255;
3020 }
3021 }
3022
3023 return jwin_edit_proc(msg,d,c);
3024 }
3025
3026 int32_t jwin_numedit_byte_proc(int32_t msg,DIALOG *d,int32_t c)
3027 {
3028 if ( (atoi((char*)d->dp)) > 255 )
3029 {
3030 strcpy((char*)d->dp,"255\0");
3031 return jwin_numedit_proc(msg,d,c);
3032 }
3033 else if ( (atoi((char*)d->dp)) < 0 )
3034 {
3035 strcpy((char*)d->dp,"0\0");
3036 return jwin_numedit_proc(msg,d,c);
3037 }
3038
3039 return jwin_numedit_proc(msg,d,c);
3040 }
3041
3042 int32_t jwin_numedit_short_proc(int32_t msg,DIALOG *d,int32_t c)
3043 {
3044 if ( (atoi((char*)d->dp)) > 65535 )
3045 {
3046 strcpy((char*)d->dp,"65535\0");
3047 return jwin_numedit_proc(msg,d,c);
3048 }
3049 else if ( (atoi((char*)d->dp)) < 0 )
3050 {
3051 strcpy((char*)d->dp,"0\0");
3052 return jwin_numedit_proc(msg,d,c);
3053 }
3054
3055 return jwin_numedit_proc(msg,d,c);
3056 }
3057
3058 int32_t jwin_numedit_zscriptint_proc(int32_t msg,DIALOG *d,int32_t c)
3059 {
3060 if ( (atoi((char*)d->dp)) > 214748 )
3061 {
3062 strcpy((char*)d->dp,"214748\0");
3063 return jwin_numedit_proc(msg,d,c);
3064 }
3065 else if ( (atoi((char*)d->dp)) < -214748 )
3066 {
3067 strcpy((char*)d->dp,"-214748\0");
3068 return jwin_numedit_proc(msg,d,c);
3069 }
3070
3071 return jwin_numedit_proc(msg,d,c);
3072 }
3073
3074 int32_t jwin_numedit_sshort_proc(int32_t msg,DIALOG *d,int32_t c)
3075 {
3076 if ( (atoi((char*)d->dp)) > 32767 )
3077 {
3078 strcpy((char*)d->dp,"32767\0");
3079 return jwin_numedit_proc(msg,d,c);
3080 }
3081 else if ( (atoi((char*)d->dp)) < -32768 )
3082 {
3083 strcpy((char*)d->dp,"-32768\0");
3084 return jwin_numedit_proc(msg,d,c);
3085 }
3086
3087 return jwin_numedit_proc(msg,d,c);
3088 }
3089
3090 int32_t jwin_numedit_sbyte_proc(int32_t msg,DIALOG *d,int32_t c)
3091 {
3092 if ( (atoi((char*)d->dp)) > 127 )
3093 {
3094 strcpy((char*)d->dp,"127\0");
3095 return jwin_numedit_proc(msg,d,c);
3096 }
3097 else if ( (atoi((char*)d->dp)) < -128 )
3098 {
3099 strcpy((char*)d->dp,"-128\0");
3100 return jwin_numedit_proc(msg,d,c);
3101 }
3102
3103 return jwin_numedit_proc(msg,d,c);
3104 }
3105
3106 // Special numedit procs
3107
3108 void trim_trailing_0s(char* str, bool leaveDec = false)
3109 {
3110 bool foundDec = false;
3111 for(int32_t q = 0; str[q]; ++q)
3112 {
3113 if(str[q] == '.')
3114 {
3115 foundDec = true;
3116 break;
3117 }
3118 }
3119 if(!foundDec) return; //No decimal place, thus no trailing 0's.
3120 for(int32_t q = strlen(str)-1; q > 0; --q)
3121 {
3122 if(str[q] == '0' && (!leaveDec || str[q-1] != '.'))
3123 {
3124 str[q] = 0;
3125 }
3126 else if(str[q] == '.')
3127 {
3128 str[q] = 0;
3129 return;
3130 }
3131 else return;
3132 }
3133 }
3134 int32_t jwin_swapbtn_proc(int32_t msg, DIALOG* d, int32_t c)
3135 {
3136 static const char* swp[nswapMAX] = {"D", "H", "LD", "LH", "B"};
3137 d->dp = (void*)swp[d->d1&0xF];
3138 //d1 is (0xF0 = old val, 0x0F = new val)
3139 //d2 is max val
3140 if(d->d2 < 2 || d->d2 > nswapMAX) return D_O_K; //Not setup yet, or bad value
3141 DIALOG* relproc = (DIALOG*)d->dp3;
3142 GUI::TextField *tf_obj = nullptr;
3143 if(d->d2 > nswapBOOL) tf_obj = (GUI::TextField*)relproc->dp3;
3144 int32_t ret = jwin_button_proc(msg, d, c);
3145 if(d->flags & D_SELECTED) //On selection
3146 {
3147 d->d1 = ((d->d1&0x0F)<<4) | (((d->d1&0x0F)+1)%d->d2);
3148 d->dp = (void*)swp[d->d1&0xF];
3149 d->flags &= ~D_SELECTED;
3150 if(tf_obj) tf_obj->refresh_cb_swap();
3151 if(relproc)
3152 {
3153 object_message(relproc, MSG_DRAW, 0);
3154 }
3155 object_message(d, MSG_DRAW, 0);
3156 }
3157 return ret;
3158 }
3159 int32_t jwin_numedit_swap_byte_proc(int32_t msg, DIALOG *d, int32_t c)
3160 {
3161 DIALOG* swapbtn;
3162 if(d->flags&D_NEW_GUI)
3163 {
3164 swapbtn = d+1;
3165 }
3166 else swapbtn = (DIALOG*)d->dp3;
3167 if(!swapbtn) return D_O_K;
3168 if(msg==MSG_START) //Setup the swapbtn
3169 {
3170 d->bg = 0;
3171 swapbtn->d2 = 2; //Max states
3172 auto ty = swapbtn->d1&0xF;
3173 if(unsigned(ty) > swapbtn->d2)
3174 swapbtn->d1 &= ~0xF;
3175 swapbtn->dp3 = (void*)d;
3176 }
3177 int32_t ret = D_O_K;
3178 int32_t ntype = swapbtn->d1&0xF,
3179 otype = swapbtn->d1>>4;
3180
3181 char* str = (char*)d->dp;
3182 int32_t v = 0;
3183 if(msg == MSG_START)
3184 v = d->fg;
3185 else switch(otype)
3186 {
3187 case nswapDEC:
3188 v = atoi(str);
3189 break;
3190 case nswapHEX:
3191 v = zc_xtoi(str);
3192 break;
3193 }
3194 byte b;
3195 if ( v > 255 )
3196 b=255;
3197 else if ( v < 0 )
3198 b=0;
3199 else b = (byte)v;
3200 if(msg==MSG_CHAR && ((c&255)=='-'))
3201 {
3202 //unsigned//b = -b;
3203 c &= ~255;
3204 }
3205 if(unsigned(v) != b || otype != ntype || msg == MSG_START)
3206 {
3207 switch(ntype)
3208 {
3209 case nswapDEC:
3210 sprintf(str, "%d", b);
3211 break;
3212 case nswapHEX:
3213 sprintf(str, "%X", b);
3214 break;
3215 }
3216 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3217 }
3218
3219 if(d->fg != b)
3220 {
3221 d->fg = b; //Store numeric data
3222 GUI_EVENT(d, geUPDATE_SWAP);
3223 }
3224 switch(ntype)
3225 {
3226 case nswapDEC:
3227 d->d1 = 3; //3 digits max
3228 ret |= jwin_numedit_proc(msg, d, c);
3229 break;
3230 case nswapHEX:
3231 d->d1 = 2; //2 digits max
3232 if(msg == MSG_CHAR && isalpha(c&255)) //always capitalize
3233 c = (c&~255) | (toupper(c&255));
3234 ret |= jwin_hexedit_proc(msg, d, c);
3235 break;
3236 }
3237
3238 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3239
3240 return ret;
3241 }
3242 #define INC_TF_CURSORS(val,inc,max) \
3243 do \
3244 { \
3245 int32_t scursor = (val & 0xFFFF)+inc; \
3246 int32_t ecursor = (val & 0xFFFF0000) >> 16; \
3247 bool valid_ecursor = ecursor != 0xFFFF; \
3248 if(valid_ecursor) ecursor += inc; \
3249 if(inc < 0) \
3250 { \
3251 if(scursor < 0) scursor = 0; \
3252 if(valid_ecursor && ecursor < 0) ecursor = 0; \
3253 } \
3254 else \
3255 { \
3256 if(scursor > max) scursor = max; \
3257 if(valid_ecursor && ecursor > max) ecursor = max; \
3258 } \
3259 val = scursor | (ecursor<<16); \
3260 } while(false)
3261 int32_t jwin_numedit_swap_sshort_proc(int32_t msg, DIALOG *d, int32_t c)
3262 {
3263 const size_t maxlen = 7;
3264 DIALOG* swapbtn;
3265 if(d->flags&D_NEW_GUI)
3266 {
3267 swapbtn = d+1;
3268 }
3269 else swapbtn = (DIALOG*)d->dp3;
3270 if(!swapbtn) return D_O_K;
3271 if(msg==MSG_START) //Setup the swapbtn
3272 {
3273 d->bg = 0;
3274 swapbtn->d2 = 2; //Max states
3275 auto ty = swapbtn->d1&0xF;
3276 if(unsigned(ty) > swapbtn->d2)
3277 swapbtn->d1 &= ~0xF;
3278 swapbtn->dp3 = (void*)d;
3279 }
3280 int32_t ret = D_O_K;
3281 int32_t ntype = swapbtn->d1&0xF,
3282 otype = swapbtn->d1>>4;
3283
3284 char* str = (char*)d->dp;
3285 int32_t v = 0;
3286 if(msg == MSG_START)
3287 v = d->fg;
3288 else switch(otype)
3289 {
3290 case nswapDEC:
3291 v = atoi(str);
3292 break;
3293 case nswapHEX:
3294 v = zc_xtoi(str);
3295 break;
3296 }
3297 int16_t b;
3298 if ( v > 32767 )
3299 b=32767;
3300 else if ( v < -32768 )
3301 b=-32768;
3302 else b = (int16_t)v;
3303 bool queued_neg = d->bg;
3304 if(msg==MSG_CHAR && ((c&255)=='-'))
3305 {
3306 if(b)
3307 {
3308 b = -b;
3309 v = b;
3310 if(b<0)
3311 {
3312 if(str[0] != '-')
3313 {
3314 char buf[16] = {0};
3315 strcpy(buf, str);
3316 sprintf(str, "-%s", buf);
3317 INC_TF_CURSORS(d->d2,1,strlen(str));
3318 }
3319 }
3320 else if(str[0] == '-')
3321 {
3322 char buf[16] = {0};
3323 strcpy(buf, str);
3324 sprintf(str, "%s", buf+1);
3325 INC_TF_CURSORS(d->d2,-1,strlen(str));
3326 }
3327 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3328 }
3329 else queued_neg = !queued_neg; //queue the negative
3330 c &= ~255;
3331 ret |= D_USED_CHAR;
3332 }
3333 if(b && queued_neg)
3334 {
3335 //b = -b; //actually, 'atoi' handles it for us.....
3336 queued_neg = false;
3337 }
3338 if(bool(d->bg) != queued_neg)
3339 {
3340 d->bg = queued_neg;
3341 if(queued_neg)
3342 {
3343 if(str[0] != '-')
3344 {
3345 char buf[16] = {0};
3346 strcpy(buf, str);
3347 sprintf(str, "-%s", buf);
3348 INC_TF_CURSORS(d->d2,1,strlen(str));
3349 }
3350 }
3351 else if(!b && str[0] == '-')
3352 {
3353 char buf[16] = {0};
3354 strcpy(buf, str);
3355 sprintf(str, "%s", buf+1);
3356 INC_TF_CURSORS(d->d2,-1,strlen(str));
3357 }
3358 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3359 }
3360 if(v != b || otype != ntype || msg == MSG_START)
3361 {
3362 switch(ntype)
3363 {
3364 case nswapDEC:
3365 sprintf(str, "%d", b);
3366 break;
3367 case nswapHEX:
3368 if(b<0)
3369 sprintf(str, "-%X", -b);
3370 else sprintf(str, "%X", b);
3371 break;
3372 }
3373 d->d2 = 0xFFFF0000|strlen(str);
3374 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3375 }
3376
3377 if(d->fg != b)
3378 {
3379 d->fg = b; //Store numeric data
3380 GUI_EVENT(d, geUPDATE_SWAP);
3381 }
3382 bool rev_d2 = false;
3383 int32_t old_d2 = d->d2;
3384 int32_t ref_d2;
3385 if(msg == MSG_CHAR && queued_neg)
3386 {
3387 auto scursor = d->d2 & 0xFFFF;
3388 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3389 if(!scursor)
3390 {
3391 rev_d2 = true;
3392 INC_TF_CURSORS(d->d2,1,strlen(str));
3393 ref_d2 = d->d2;
3394 }
3395 }
3396 switch(ntype)
3397 {
3398 case nswapDEC:
3399 d->d1 = 6; //6 digits max (incl '-')
3400 ret |= jwin_numedit_proc(msg, d, c);
3401 break;
3402 case nswapHEX:
3403 d->d1 = 5; //5 digits max (incl '-')
3404 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3405 c = (c&~255) | (toupper(c&255));
3406 ret |= jwin_hexedit_proc(msg, d, c);
3407 break;
3408 }
3409 if(rev_d2 && ref_d2 == d->d2)
3410 {
3411 d->d2 = old_d2;
3412 }
3413
3414 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3415
3416 return ret;
3417 }
3418 int32_t jwin_numedit_swap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
3419 {
3420 const size_t maxlen = 13;
3421 DIALOG* swapbtn;
3422 if(d->flags&D_NEW_GUI)
3423 {
3424 swapbtn = d+1;
3425 }
3426 else swapbtn = (DIALOG*)d->dp3;
3427 if(!swapbtn) return D_O_K;
3428 if(msg==MSG_START) //Setup the swapbtn
3429 {
3430 d->bg = 0;
3431 swapbtn->d2 = 4; //Max states
3432 auto ty = swapbtn->d1&0xF;
3433 if(unsigned(ty) > swapbtn->d2)
3434 swapbtn->d1 &= ~0xF;
3435 swapbtn->dp3 = (void*)d;
3436 }
3437 int32_t ret = D_O_K;
3438 int32_t ntype = swapbtn->d1&0xF,
3439 otype = swapbtn->d1>>4;
3440
3441 char* str = (char*)d->dp;
3442 int64_t v = 0;
3443 if(msg == MSG_START)
3444 v = d->fg;
3445 else switch(otype)
3446 {
3447 case nswapDEC:
3448 if(char *ptr = strchr(str, '.'))
3449 {
3450 char tempstr[32] = {0};
3451 strcpy(tempstr, str);
3452 for(int32_t q = 0; q < 4; ++q)
3453 tempstr[strlen(str)+q]='0';
3454 ptr = strchr(tempstr, '.');
3455 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3456 v = atoi(tempstr);
3457 v *= 10000;
3458 if(tempstr[0] == '-')
3459 v -= atoi(ptr);
3460 else v += atoi(ptr);
3461 }
3462 else
3463 {
3464 v = atoi(str);
3465 v *= 10000;
3466 }
3467 break;
3468 case nswapHEX:
3469 if(char *ptr = strchr(str, '.'))
3470 {
3471 char tempstr[32] = {0};
3472 strcpy(tempstr, str);
3473 for(int32_t q = 0; q < 4; ++q)
3474 tempstr[strlen(str)+q]='0';
3475 ptr = strchr(tempstr, '.');
3476 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3477 v = zc_xtoi(tempstr);
3478 v *= 10000;
3479 if(tempstr[0] == '-')
3480 v -= atoi(ptr);
3481 else v += atoi(ptr);
3482 }
3483 else
3484 {
3485 v = zc_xtoi(str);
3486 v *= 10000;
3487 }
3488 break;
3489 case nswapLDEC:
3490 v = zc_atoi64(str);
3491 break;
3492 case nswapLHEX:
3493 v = zc_xtoi64(str);
3494 break;
3495 }
3496 int32_t b;
3497 if ( v > 2147483647 )
3498 b=2147483647;
3499 else if ( v < INT_MIN )
3500 b=INT_MIN;
3501 else b = (int32_t)v;
3502 bool queued_neg = d->bg;
3503 if(msg==MSG_CHAR && ((c&255)=='-'))
3504 {
3505 if(b)
3506 {
3507 if(b==INT_MIN)
3508 ++b;
3509 b = -b;
3510 v = b;
3511 if(b<0)
3512 {
3513 if(str[0] != '-')
3514 {
3515 char buf[16] = {0};
3516 strcpy(buf, str);
3517 sprintf(str, "-%s", buf);
3518 INC_TF_CURSORS(d->d2,1,strlen(str));
3519 }
3520 }
3521 else if(str[0] == '-')
3522 {
3523 char buf[16] = {0};
3524 strcpy(buf, str);
3525 sprintf(str, "%s", buf+1);
3526 INC_TF_CURSORS(d->d2,-1,strlen(str));
3527 }
3528 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3529 }
3530 else queued_neg = !queued_neg; //queue negative
3531 c &= ~255;
3532 ret |= D_USED_CHAR;
3533 }
3534 if(b && queued_neg)
3535 {
3536 //b = -b; //actually, 'atoi' handles it for us.....
3537 queued_neg = false;
3538 }
3539 if(bool(d->bg) != queued_neg)
3540 {
3541 d->bg = queued_neg;
3542 if(queued_neg)
3543 {
3544 if(str[0] != '-')
3545 {
3546 char buf[16] = {0};
3547 strcpy(buf, str);
3548 sprintf(str, "-%s", buf);
3549 INC_TF_CURSORS(d->d2,1,strlen(str));
3550 }
3551 }
3552 else if(!b && str[0] == '-')
3553 {
3554 char buf[16] = {0};
3555 strcpy(buf, str);
3556 sprintf(str, "%s", buf+1);
3557 INC_TF_CURSORS(d->d2,-1,strlen(str));
3558 }
3559 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3560 }
3561 if(v != b || otype != ntype || msg == MSG_START)
3562 {
3563 switch(ntype)
3564 {
3565 case nswapDEC:
3566 if(b < 0)
3567 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
3568 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
3569 trim_trailing_0s(str);
3570 break;
3571 case nswapHEX:
3572 if(b<0)
3573 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
3574 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
3575 trim_trailing_0s(str);
3576 break;
3577 case nswapLDEC:
3578 sprintf(str, "%d", b);
3579 break;
3580 case nswapLHEX:
3581 if(b<0)
3582 sprintf(str, "-%X", -b);
3583 else sprintf(str, "%X", b);
3584 break;
3585 }
3586 d->d2 = 0xFFFF0000|strlen(str);
3587 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3588 }
3589 if(d->fg != b)
3590 {
3591 d->fg = b; //Store numeric data
3592 GUI_EVENT(d, geUPDATE_SWAP);
3593 }
3594 if(msg==MSG_CHAR && ((c&255)=='.'))
3595 {
3596 if(ntype >= nswapLDEC) //No '.' in long modes
3597 c&=~255;
3598 else
3599 {
3600 for(int32_t q = 0; str[q]; ++q)
3601 {
3602 if(str[q] == '.') //Only one '.'
3603 {
3604 c&=~255;
3605 break;
3606 }
3607 }
3608 }
3609 }
3610 bool rev_d2 = false;
3611 int32_t old_d2 = d->d2;
3612 int32_t ref_d2;
3613 if(msg == MSG_CHAR && queued_neg)
3614 {
3615 auto scursor = d->d2 & 0xFFFF;
3616 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3617 if(!scursor)
3618 {
3619 rev_d2 = true;
3620 INC_TF_CURSORS(d->d2,1,strlen(str));
3621 ref_d2 = d->d2;
3622 }
3623 }
3624 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3625 switch(ntype)
3626 {
3627 case nswapDEC:
3628 d->d1 = 12; //12 digits max (incl '-', '.')
3629 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
3630 {
3631 int32_t p = 0;
3632 for(int32_t q = 0; str[q]; ++q)
3633 {
3634 if(str[q]=='.')
3635 {
3636 if((d->d2&0x0000FFFF) <= q)
3637 break; //typing before the '.'
3638 ++p;
3639 }
3640 else if(p) ++p;
3641 }
3642 if(p>=5) //too many chars after '.'
3643 c&=~255;
3644 }
3645 ret |= jwin_numedit_proc(msg, d, c);
3646 break;
3647 case nswapHEX:
3648 d->d1 = 11; //11 digits max (incl '-', '.')
3649 if(msg==MSG_CHAR && !editproc_special_key(c))
3650 {
3651 if(!((c&255)=='.'||isxdigit(c&255)))
3652 c&=~255;
3653 else if(isxdigit(c&255) && !isdigit(c&255))
3654 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
3655 {
3656 if(str[q] == '.') //No hex digits to the right of the '.'
3657 {
3658 c&=~255;
3659 break;
3660 }
3661 }
3662 if((c&255) && !areaselect)
3663 {
3664 int32_t p = 0;
3665 for(int32_t q = 0; str[q]; ++q)
3666 {
3667 if(str[q]=='.')
3668 {
3669 if((d->d2&0x0000FFFF) <= q)
3670 break; //typing before the '.'
3671 ++p;
3672 }
3673 else if(p) ++p;
3674 }
3675 if(p>=5) //too many chars after '.'
3676 c&=~255;
3677 }
3678 if(isalpha(c&255)) //always capitalize
3679 c = (c&~255) | (toupper(c&255));
3680 }
3681 ret |= jwin_hexedit_proc(msg, d, c);
3682 break;
3683 case nswapLDEC:
3684 d->d1 = 11; //11 digits max (incl '-')
3685 ret |= jwin_numedit_proc(msg, d, c);
3686 break;
3687 case nswapLHEX:
3688 d->d1 = 9; //9 digits max (incl '-')
3689 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
3690 c = (c&~255) | (toupper(c&255));
3691 ret |= jwin_hexedit_proc(msg, d, c);
3692 break;
3693 }
3694 if(rev_d2 && ref_d2 == d->d2)
3695 {
3696 d->d2 = old_d2;
3697 }
3698
3699 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3700
3701 return ret;
3702 }
3703 int32_t jwin_numedit_swap_zsint_nodec_proc(int32_t msg, DIALOG *d, int32_t c)
3704 {
3705 const size_t maxlen = 7;
3706 DIALOG* swapbtn;
3707 if(d->flags&D_NEW_GUI)
3708 {
3709 swapbtn = d+1;
3710 }
3711 else swapbtn = (DIALOG*)d->dp3;
3712 if(!swapbtn) return D_O_K;
3713 if(msg==MSG_START) //Setup the swapbtn
3714 {
3715 d->bg = 0;
3716 swapbtn->d2 = 2; //Max states
3717 auto ty = swapbtn->d1&0xF;
3718 if(unsigned(ty) > swapbtn->d2)
3719 swapbtn->d1 &= ~0xF;
3720 swapbtn->dp3 = (void*)d;
3721 }
3722 int32_t ret = D_O_K;
3723 int32_t ntype = swapbtn->d1&0xF,
3724 otype = swapbtn->d1>>4;
3725
3726 char* str = (char*)d->dp;
3727 int64_t v = 0;
3728 if(msg == MSG_START)
3729 v = d->fg;
3730 else switch(otype)
3731 {
3732 case nswapDEC:
3733 v = atoi(str);
3734 v *= 10000;
3735 break;
3736 case nswapHEX:
3737 v = zc_xtoi(str);
3738 v *= 10000;
3739 break;
3740 }
3741 int32_t b;
3742 if ( v > 2147480000 )
3743 b=2147480000;
3744 else if ( v < -2147480000 )
3745 b=-2147480000;
3746 else b = (int32_t)v;
3747 bool queued_neg = d->bg;
3748 if(msg==MSG_CHAR && ((c&255)=='-'))
3749 {
3750 if(b)
3751 {
3752 if(b==INT_MIN)
3753 ++b;
3754 b = -b;
3755 v = b;
3756 if(b<0)
3757 {
3758 if(str[0] != '-')
3759 {
3760 char buf[16] = {0};
3761 strcpy(buf, str);
3762 sprintf(str, "-%s", buf);
3763 INC_TF_CURSORS(d->d2,1,strlen(str));
3764 }
3765 }
3766 else if(str[0] == '-')
3767 {
3768 char buf[16] = {0};
3769 strcpy(buf, str);
3770 sprintf(str, "%s", buf+1);
3771 INC_TF_CURSORS(d->d2,-1,strlen(str));
3772 }
3773 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3774 }
3775 else queued_neg = !queued_neg; //queue negative
3776 c &= ~255;
3777 ret |= D_USED_CHAR;
3778 }
3779 if(b && queued_neg)
3780 {
3781 //b = -b; //actually, 'atoi' handles it for us.....
3782 queued_neg = false;
3783 }
3784 if(bool(d->bg) != queued_neg)
3785 {
3786 d->bg = queued_neg;
3787 if(queued_neg)
3788 {
3789 if(str[0] != '-')
3790 {
3791 char buf[16] = {0};
3792 strcpy(buf, str);
3793 sprintf(str, "-%s", buf);
3794 INC_TF_CURSORS(d->d2,1,strlen(str));
3795 }
3796 }
3797 else if(!b && str[0] == '-')
3798 {
3799 char buf[16] = {0};
3800 strcpy(buf, str);
3801 sprintf(str, "%s", buf+1);
3802 INC_TF_CURSORS(d->d2,-1,strlen(str));
3803 }
3804 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3805 }
3806 if(v != b || otype != ntype || msg == MSG_START)
3807 {
3808 switch(ntype)
3809 {
3810 case nswapDEC:
3811 if(b < 0)
3812 sprintf(str, "-%ld", abs(b/10000L));
3813 else sprintf(str, "%ld", b/10000L);
3814 break;
3815 case nswapHEX:
3816 if(b<0)
3817 sprintf(str, "-%lX", abs(b/10000L));
3818 else sprintf(str, "%lX", b/10000L);
3819 break;
3820 }
3821 d->d2 = 0xFFFF0000|strlen(str);
3822 if(msg != MSG_DRAW) ret |= D_REDRAWME;
3823 }
3824 if(d->fg != b)
3825 {
3826 d->fg = b; //Store numeric data
3827 GUI_EVENT(d, geUPDATE_SWAP);
3828 }
3829 if(msg==MSG_CHAR && ((c&255)=='.'))
3830 {
3831 c&=~255; //no '.' in nodec version
3832 }
3833 bool rev_d2 = false;
3834 int32_t old_d2 = d->d2;
3835 int32_t ref_d2;
3836 if(msg == MSG_CHAR && queued_neg)
3837 {
3838 auto scursor = d->d2 & 0xFFFF;
3839 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
3840 if(!scursor)
3841 {
3842 rev_d2 = true;
3843 INC_TF_CURSORS(d->d2,1,strlen(str));
3844 ref_d2 = d->d2;
3845 }
3846 }
3847 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
3848 switch(ntype)
3849 {
3850 case nswapDEC:
3851 d->d1 = 7; //7 digits max (incl '-')
3852 ret |= jwin_numedit_proc(msg, d, c);
3853 break;
3854 case nswapHEX:
3855 d->d1 = 6; //6 digits max (incl '-')
3856 if(msg==MSG_CHAR && !editproc_special_key(c))
3857 {
3858 if(!isxdigit(c&255))
3859 c&=~255;
3860 if(isalpha(c&255)) //always capitalize
3861 c = (c&~255) | (toupper(c&255));
3862 }
3863 ret |= jwin_hexedit_proc(msg, d, c);
3864 break;
3865 }
3866 if(rev_d2 && ref_d2 == d->d2)
3867 {
3868 d->d2 = old_d2;
3869 }
3870
3871 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
3872
3873 return ret;
3874 }
3875 int32_t jwin_numedit_swap_zsint2_proc(int32_t msg, DIALOG *d, int32_t c)
3876 {
3877 const size_t maxlen = 13;
3878 DIALOG* swapbtn;
3879 ASSERT(d->flags&D_NEW_GUI);
3880 swapbtn = d+1;
3881 if(!swapbtn) return D_O_K;
3882 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
3883 if(!tf_obj) return D_O_K;
3884 if(msg==MSG_START) //Setup the swapbtn
3885 {
3886 d->bg = 0;
3887 swapbtn->d2 = 5; //Max states
3888 auto ty = swapbtn->d1&0xF;
3889 if(unsigned(ty) > swapbtn->d2)
3890 swapbtn->d1 &= ~0xF;
3891 swapbtn->dp3 = (void*)d;
3892 }
3893 int32_t ret = D_O_K;
3894 int32_t ntype = swapbtn->d1&0xF,
3895 otype = swapbtn->d1>>4;
3896 if(otype==nswapBOOL || ntype == nswapBOOL)
3897 {
3898 if(otype != ntype)
3899 {
3900 tf_obj->refresh_cb_swap();
3901 }
3902 if(ntype == nswapBOOL)
3903 {
3904 swapbtn->d1 = (ntype<<4)|ntype;
3905 return D_O_K;
3906 }
3907 }
3908
3909 char* str = (char*)d->dp;
3910 int64_t v = 0;
3911 if(msg == MSG_START)
3912 v = d->fg;
3913 else switch(otype)
3914 {
3915 case nswapDEC:
3916 if(char *ptr = strchr(str, '.'))
3917 {
3918 char tempstr[32] = {0};
3919 strcpy(tempstr, str);
3920 for(int32_t q = 0; q < 4; ++q)
3921 tempstr[strlen(str)+q]='0';
3922 ptr = strchr(tempstr, '.');
3923 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3924 v = atoi(tempstr);
3925 v *= 10000;
3926 if(tempstr[0] == '-')
3927 v -= atoi(ptr);
3928 else v += atoi(ptr);
3929 }
3930 else
3931 {
3932 v = atoi(str);
3933 v *= 10000;
3934 }
3935 break;
3936 case nswapHEX:
3937 if(char *ptr = strchr(str, '.'))
3938 {
3939 char tempstr[32] = {0};
3940 strcpy(tempstr, str);
3941 for(int32_t q = 0; q < 4; ++q)
3942 tempstr[strlen(str)+q]='0';
3943 ptr = strchr(tempstr, '.');
3944 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
3945 v = zc_xtoi(tempstr);
3946 v *= 10000;
3947 if(tempstr[0] == '-')
3948 v -= atoi(ptr);
3949 else v += atoi(ptr);
3950 }
3951 else
3952 {
3953 v = zc_xtoi(str);
3954 v *= 10000;
3955 }
3956 break;
3957 case nswapLDEC:
3958 v = zc_atoi64(str);
3959 break;
3960 case nswapLHEX:
3961 v = zc_xtoi64(str);
3962 break;
3963 case nswapBOOL:
3964 v = d->fg;
3965 break;
3966 }
3967 int32_t b;
3968 if ( v > 2147483647 )
3969 b=2147483647;
3970 else if ( v < INT_MIN )
3971 b=INT_MIN;
3972 else b = (int32_t)v;
3973 bool queued_neg = d->bg;
3974 if(msg==MSG_CHAR && ((c&255)=='-'))
3975 {
3976 if(b)
3977 {
3978 if(b==INT_MIN)
3979 ++b;
3980 b = -b;
3981 v = b;
3982 if(b<0)
3983 {
3984 if(str[0] != '-')
3985 {
3986 char buf[16] = {0};
3987 strcpy(buf, str);
3988 sprintf(str, "-%s", buf);
3989 INC_TF_CURSORS(d->d2,1,strlen(str));
3990 }
3991 }
3992 else if(str[0] == '-')
3993 {
3994 char buf[16] = {0};
3995 strcpy(buf, str);
3996 sprintf(str, "%s", buf+1);
3997 INC_TF_CURSORS(d->d2,-1,strlen(str));
3998 }
3999 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4000 }
4001 else queued_neg = !queued_neg; //queue negative
4002 c &= ~255;
4003 ret |= D_USED_CHAR;
4004 }
4005 if(b && queued_neg)
4006 {
4007 //b = -b; //actually, 'atoi' handles it for us.....
4008 queued_neg = false;
4009 }
4010 if(bool(d->bg) != queued_neg)
4011 {
4012 d->bg = queued_neg;
4013 if(queued_neg)
4014 {
4015 if(str[0] != '-')
4016 {
4017 char buf[16] = {0};
4018 strcpy(buf, str);
4019 sprintf(str, "-%s", buf);
4020 INC_TF_CURSORS(d->d2,1,strlen(str));
4021 }
4022 }
4023 else if(!b && str[0] == '-')
4024 {
4025 char buf[16] = {0};
4026 strcpy(buf, str);
4027 sprintf(str, "%s", buf+1);
4028 INC_TF_CURSORS(d->d2,-1,strlen(str));
4029 }
4030 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4031 }
4032 if(v != b || otype != ntype || msg == MSG_START)
4033 {
4034 switch(ntype)
4035 {
4036 case nswapDEC:
4037 if(b < 0)
4038 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4039 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4040 trim_trailing_0s(str);
4041 break;
4042 case nswapHEX:
4043 if(b<0)
4044 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4045 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4046 trim_trailing_0s(str);
4047 break;
4048 case nswapLDEC:
4049 sprintf(str, "%d", b);
4050 break;
4051 case nswapLHEX:
4052 if(b<0)
4053 sprintf(str, "-%X", -b);
4054 else sprintf(str, "%X", b);
4055 break;
4056 }
4057 d->d2 = 0xFFFF0000|strlen(str);
4058 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4059 }
4060 if(d->fg != b)
4061 {
4062 d->fg = b; //Store numeric data
4063 GUI_EVENT(d, geUPDATE_SWAP);
4064 }
4065 if(msg==MSG_CHAR && ((c&255)=='.'))
4066 {
4067 if(ntype >= nswapLDEC) //No '.' in long modes
4068 c&=~255;
4069 else
4070 {
4071 for(int32_t q = 0; str[q]; ++q)
4072 {
4073 if(str[q] == '.') //Only one '.'
4074 {
4075 c&=~255;
4076 break;
4077 }
4078 }
4079 }
4080 }
4081 bool rev_d2 = false;
4082 int32_t old_d2 = d->d2;
4083 int32_t ref_d2;
4084 if(msg == MSG_CHAR && queued_neg)
4085 {
4086 auto scursor = d->d2 & 0xFFFF;
4087 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4088 if(!scursor)
4089 {
4090 rev_d2 = true;
4091 INC_TF_CURSORS(d->d2,1,strlen(str));
4092 ref_d2 = d->d2;
4093 }
4094 }
4095 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4096 switch(ntype)
4097 {
4098 case nswapDEC:
4099 d->d1 = 12; //12 digits max (incl '-', '.')
4100 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4101 {
4102 int32_t p = 0;
4103 for(int32_t q = 0; str[q]; ++q)
4104 {
4105 if(str[q]=='.')
4106 {
4107 if((d->d2&0x0000FFFF) <= q)
4108 break; //typing before the '.'
4109 ++p;
4110 }
4111 else if(p) ++p;
4112 }
4113 if(p>=5) //too many chars after '.'
4114 c&=~255;
4115 }
4116 ret |= jwin_numedit_proc(msg, d, c);
4117 break;
4118 case nswapHEX:
4119 d->d1 = 11; //11 digits max (incl '-', '.')
4120 if(msg==MSG_CHAR && !editproc_special_key(c))
4121 {
4122 if(!((c&255)=='.'||isxdigit(c&255)))
4123 c&=~255;
4124 else if(isxdigit(c&255) && !isdigit(c&255))
4125 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4126 {
4127 if(str[q] == '.') //No hex digits to the right of the '.'
4128 {
4129 c&=~255;
4130 break;
4131 }
4132 }
4133 if((c&255) && !areaselect)
4134 {
4135 int32_t p = 0;
4136 for(int32_t q = 0; str[q]; ++q)
4137 {
4138 if(str[q]=='.')
4139 {
4140 if((d->d2&0x0000FFFF) <= q)
4141 break; //typing before the '.'
4142 ++p;
4143 }
4144 else if(p) ++p;
4145 }
4146 if(p>=5) //too many chars after '.'
4147 c&=~255;
4148 }
4149 if(isalpha(c&255)) //always capitalize
4150 c = (c&~255) | (toupper(c&255));
4151 }
4152 ret |= jwin_hexedit_proc(msg, d, c);
4153 break;
4154 case nswapLDEC:
4155 d->d1 = 11; //11 digits max (incl '-')
4156 ret |= jwin_numedit_proc(msg, d, c);
4157 break;
4158 case nswapLHEX:
4159 d->d1 = 9; //9 digits max (incl '-')
4160 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4161 c = (c&~255) | (toupper(c&255));
4162 ret |= jwin_hexedit_proc(msg, d, c);
4163 break;
4164 }
4165 if(rev_d2 && ref_d2 == d->d2)
4166 {
4167 d->d2 = old_d2;
4168 }
4169
4170 swapbtn->d1 = (ntype<<4)|ntype; //Mark the type change processed
4171
4172 if(msg==MSG_START)
4173 tf_obj->refresh_cb_swap();
4174
4175 return ret;
4176 }
4177 int32_t jwin_numedit_noswap_zsint_proc(int32_t msg, DIALOG *d, int32_t c)
4178 {
4179 const size_t maxlen = 13;
4180 ASSERT(d->flags&D_NEW_GUI);
4181 GUI::TextField *tf_obj = (GUI::TextField*)d->dp3;
4182 if(!tf_obj) return D_O_K;
4183 int32_t ret = D_O_K;
4184 int32_t type = tf_obj->getSwapType();
4185
4186 char* str = (char*)d->dp;
4187 int64_t v = 0;
4188 if(msg == MSG_START)
4189 v = d->fg;
4190 else switch(type)
4191 {
4192 case nswapDEC:
4193 if(char *ptr = strchr(str, '.'))
4194 {
4195 char tempstr[32] = {0};
4196 strcpy(tempstr, str);
4197 for(int32_t q = 0; q < 4; ++q)
4198 tempstr[strlen(str)+q]='0';
4199 ptr = strchr(tempstr, '.');
4200 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4201 v = atoi(tempstr);
4202 v *= 10000;
4203 if(tempstr[0] == '-')
4204 v -= atoi(ptr);
4205 else v += atoi(ptr);
4206 }
4207 else
4208 {
4209 v = atoi(str);
4210 v *= 10000;
4211 }
4212 break;
4213 case nswapHEX:
4214 if(char *ptr = strchr(str, '.'))
4215 {
4216 char tempstr[32] = {0};
4217 strcpy(tempstr, str);
4218 for(int32_t q = 0; q < 4; ++q)
4219 tempstr[strlen(str)+q]='0';
4220 ptr = strchr(tempstr, '.');
4221 *ptr=0;++ptr;*(ptr+4)=0; //Nullchar at 2 positions to limit strings
4222 v = zc_xtoi(tempstr);
4223 v *= 10000;
4224 if(tempstr[0] == '-')
4225 v -= atoi(ptr);
4226 else v += atoi(ptr);
4227 }
4228 else
4229 {
4230 v = zc_xtoi(str);
4231 v *= 10000;
4232 }
4233 break;
4234 case nswapLDEC:
4235 v = zc_atoi64(str);
4236 break;
4237 case nswapLHEX:
4238 v = zc_xtoi64(str);
4239 break;
4240 case nswapBOOL:
4241 v = d->fg;
4242 break;
4243 }
4244 int32_t b;
4245 if ( v > 2147483647 )
4246 b=2147483647;
4247 else if ( v < INT_MIN )
4248 b=INT_MIN;
4249 else b = (int32_t)v;
4250 bool queued_neg = d->bg;
4251 if(msg==MSG_CHAR && ((c&255)=='-'))
4252 {
4253 if(b)
4254 {
4255 if(b==INT_MIN)
4256 ++b;
4257 b = -b;
4258 v = b;
4259 if(b<0)
4260 {
4261 if(str[0] != '-')
4262 {
4263 char buf[16] = {0};
4264 strcpy(buf, str);
4265 sprintf(str, "-%s", buf);
4266 INC_TF_CURSORS(d->d2,1,strlen(str));
4267 }
4268 }
4269 else if(str[0] == '-')
4270 {
4271 char buf[16] = {0};
4272 strcpy(buf, str);
4273 sprintf(str, "%s", buf+1);
4274 INC_TF_CURSORS(d->d2,-1,strlen(str));
4275 }
4276 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4277 }
4278 else queued_neg = !queued_neg; //queue negative
4279 c &= ~255;
4280 ret |= D_USED_CHAR;
4281 }
4282 if(b && queued_neg)
4283 {
4284 //b = -b; //actually, 'atoi' handles it for us.....
4285 queued_neg = false;
4286 }
4287 if(bool(d->bg) != queued_neg)
4288 {
4289 d->bg = queued_neg;
4290 if(queued_neg)
4291 {
4292 if(str[0] != '-')
4293 {
4294 char buf[16] = {0};
4295 strcpy(buf, str);
4296 sprintf(str, "-%s", buf);
4297 INC_TF_CURSORS(d->d2,1,strlen(str));
4298 }
4299 }
4300 else if(!b && str[0] == '-')
4301 {
4302 char buf[16] = {0};
4303 strcpy(buf, str);
4304 sprintf(str, "%s", buf+1);
4305 INC_TF_CURSORS(d->d2,-1,strlen(str));
4306 }
4307 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4308 }
4309 if(v != b || msg == MSG_START)
4310 {
4311 switch(type)
4312 {
4313 case nswapDEC:
4314 if(b < 0)
4315 sprintf(str, "-%ld.%04ld", abs(b/10000L), abs(b%10000L));
4316 else sprintf(str, "%ld.%04ld", b/10000L, b%10000L);
4317 trim_trailing_0s(str);
4318 break;
4319 case nswapHEX:
4320 if(b<0)
4321 sprintf(str, "-%lX.%04ld", abs(b/10000L), abs(b%10000L));
4322 else sprintf(str, "%lX.%04ld", b/10000L, abs(b%10000L));
4323 trim_trailing_0s(str);
4324 break;
4325 case nswapLDEC:
4326 sprintf(str, "%d", b);
4327 break;
4328 case nswapLHEX:
4329 if(b<0)
4330 sprintf(str, "-%X", -b);
4331 else sprintf(str, "%X", b);
4332 break;
4333 }
4334 d->d2 = 0xFFFF0000|strlen(str);
4335 if(msg != MSG_DRAW) ret |= D_REDRAWME;
4336 }
4337 if(d->fg != b)
4338 {
4339 d->fg = b; //Store numeric data
4340 GUI_EVENT(d, geUPDATE_SWAP);
4341 }
4342 if(msg==MSG_CHAR && ((c&255)=='.'))
4343 {
4344 if(type >= nswapLDEC) //No '.' in long modes
4345 c&=~255;
4346 else
4347 {
4348 for(int32_t q = 0; str[q]; ++q)
4349 {
4350 if(str[q] == '.') //Only one '.'
4351 {
4352 c&=~255;
4353 break;
4354 }
4355 }
4356 }
4357 }
4358 bool rev_d2 = false;
4359 int32_t old_d2 = d->d2;
4360 int32_t ref_d2;
4361 if(msg == MSG_CHAR && queued_neg)
4362 {
4363 auto scursor = d->d2 & 0xFFFF;
4364 auto ecursor = (d->d2 & 0xFFFF0000) >> 16;
4365 if(!scursor)
4366 {
4367 rev_d2 = true;
4368 INC_TF_CURSORS(d->d2,1,strlen(str));
4369 ref_d2 = d->d2;
4370 }
4371 }
4372 bool areaselect = (d->d2 & 0xFFFF0000) != 0xFFFF0000;
4373 switch(type)
4374 {
4375 case nswapDEC:
4376 d->d1 = 12; //12 digits max (incl '-', '.')
4377 if(msg==MSG_CHAR && !editproc_special_key(c) && !areaselect)
4378 {
4379 int32_t p = 0;
4380 for(int32_t q = 0; str[q]; ++q)
4381 {
4382 if(str[q]=='.')
4383 {
4384 if((d->d2&0x0000FFFF) <= q)
4385 break; //typing before the '.'
4386 ++p;
4387 }
4388 else if(p) ++p;
4389 }
4390 if(p>=5) //too many chars after '.'
4391 c&=~255;
4392 }
4393 ret |= jwin_numedit_proc(msg, d, c);
4394 break;
4395 case nswapHEX:
4396 d->d1 = 11; //11 digits max (incl '-', '.')
4397 if(msg==MSG_CHAR && !editproc_special_key(c))
4398 {
4399 if(!((c&255)=='.'||isxdigit(c&255)))
4400 c&=~255;
4401 else if(isxdigit(c&255) && !isdigit(c&255))
4402 for(int32_t q = 0; q < (d->d2&0x0000FFFF) && str[q]; ++q)
4403 {
4404 if(str[q] == '.') //No hex digits to the right of the '.'
4405 {
4406 c&=~255;
4407 break;
4408 }
4409 }
4410 if((c&255) && !areaselect)
4411 {
4412 int32_t p = 0;
4413 for(int32_t q = 0; str[q]; ++q)
4414 {
4415 if(str[q]=='.')
4416 {
4417 if((d->d2&0x0000FFFF) <= q)
4418 break; //typing before the '.'
4419 ++p;
4420 }
4421 else if(p) ++p;
4422 }
4423 if(p>=5) //too many chars after '.'
4424 c&=~255;
4425 }
4426 if(isalpha(c&255)) //always capitalize
4427 c = (c&~255) | (toupper(c&255));
4428 }
4429 ret |= jwin_hexedit_proc(msg, d, c);
4430 break;
4431 case nswapLDEC:
4432 d->d1 = 11; //11 digits max (incl '-')
4433 ret |= jwin_numedit_proc(msg, d, c);
4434 break;
4435 case nswapLHEX:
4436 d->d1 = 9; //9 digits max (incl '-')
4437 if(msg == MSG_CHAR && !editproc_special_key(c) && isalpha(c&255)) //always capitalize
4438 c = (c&~255) | (toupper(c&255));
4439 ret |= jwin_hexedit_proc(msg, d, c);
4440 break;
4441 }
4442 if(rev_d2 && ref_d2 == d->d2)
4443 {
4444 d->d2 = old_d2;
4445 }
4446
4447 if(msg==MSG_START)
4448 tf_obj->refresh_cb_swap();
4449
4450 return ret;
4451 }
4452
4453 /* _calc_scroll_bar:
4454 * Helps find positions of buttons on the scroll bar.
4455 */
4456 void _calc_scroll_bar(int32_t h, int32_t height, int32_t listsize, int32_t offset,
4457 int32_t *bh, int32_t *len, int32_t *pos)
4458 {
4459 *bh = zc_max(zc_min((h-4)/2, 14), 0);
4460 *len = zc_max(((h - 32) * height + listsize/2) / listsize , 6);
4461 *pos = ((h - 32 - *len) * offset) / (listsize-height);
4462 }
4463
4464 /* _handle_scrollable_click:
4465 * Helper to process a click on a scrollable object.
4466 */
4467
4468 void _handle_jwin_scrollable_scroll_click(DIALOG *d, int32_t listsize, int32_t *offset, FONT *fnt)
4469 {
4470 enum { top_btn, bottom_btn, bar, top_bar, bottom_bar };
4471
4472 int32_t xx, yy;
4473 int32_t height = (d->h-3) / (fnt ? text_height(fnt) : 1);
4474 int32_t hh = d->h - 32;
4475 int32_t obj = bar;
4476 int32_t bh, len, pos;
4477 int32_t down = 1, last_draw = 0;
4478 int32_t redraw = 0, mouse_delay = 0;
4479
4480 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4481
4482 xx = d->x + d->w - 18;
4483
4484 // find out which object is being clicked
4485
4486 yy = gui_mouse_y();
4487
4488 if(yy <= d->y+2+bh)
4489 {
4490 obj = top_btn;
4491 yy = d->y+2;
4492 }
4493 else if(yy >= d->y+d->h-2-bh)
4494 {
4495 obj = bottom_btn;
4496 yy = d->y+d->h-2-bh;
4497 }
4498 else if(d->h > 32+6)
4499 {
4500 if(yy < d->y+2+bh+pos)
4501 obj = top_bar;
4502 else if(yy >= d->y+2+bh+pos+len)
4503 obj = bottom_bar;
4504 }
4505
4506 while(gui_mouse_b())
4507 {
4508 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4509
4510 switch(obj)
4511 {
4512 case top_btn:
4513 case bottom_btn:
4514 down = mouse_in_rect(xx, yy, 16, bh);
4515
4516 if(!down)
4517 mouse_delay = 0;
4518 else
4519 {
4520 if((mouse_delay&1)==0)
4521 {
4522 if(obj==top_btn && *offset>0)
4523 {
4524 (*offset)--;
4525 redraw = 1;
4526 }
4527
4528 if(obj==bottom_btn && *offset<listsize-height)
4529 {
4530 (*offset)++;
4531 redraw = 1;
4532 }
4533 }
4534
4535 mouse_delay++;
4536 }
4537
4538 if(down!=last_draw || redraw)
4539 {
4540 vsync();
4541 d->proc(MSG_DRAW, d, 0);
4542 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, down*3);
4543 last_draw = down;
4544 }
4545
4546 break;
4547
4548 case top_bar:
4549 case bottom_bar:
4550 if(mouse_in_rect(xx, d->y+2, 16, d->h-4))
4551 {
4552 if(obj==top_bar)
4553 {
4554 if(gui_mouse_y() < d->y+2+bh+pos)
4555 yy = *offset - height;
4556 }
4557 else
4558 {
4559 if(gui_mouse_y() >= d->y+2+bh+pos+len)
4560 yy = *offset + height;
4561 }
4562
4563 if(yy < 0)
4564 yy = 0;
4565
4566 if(yy > listsize-height)
4567 yy = listsize-height;
4568
4569 if(yy != *offset)
4570 {
4571 *offset = yy;
4572 vsync();
4573 d->proc(MSG_DRAW, d, 0);
4574 }
4575 }
4576
4577 _calc_scroll_bar(d->h, height, listsize, *offset, &bh, &len, &pos);
4578
4579 if(!mouse_in_rect(xx, d->y+2+bh+pos, 16, len))
4580 break;
4581
4582 // fall through
4583
4584 case bar:
4585 default:
4586 xx = gui_mouse_y() - pos;
4587
4588 while(gui_mouse_b())
4589 {
4590 yy = (listsize * (gui_mouse_y() - xx) + hh/2) / hh;
4591
4592 if(yy > listsize-height)
4593 yy = listsize-height;
4594
4595 if(yy < 0)
4596 yy = 0;
4597
4598 bool should_redraw = false;
4599 if(yy != *offset)
4600 {
4601 *offset = yy;
4602 d->proc(MSG_DRAW, d, 0);
4603 should_redraw = true;
4604 }
4605
4606 /* let other objects continue to animate */
4607 int r = broadcast_dialog_message(MSG_IDLE, 0);
4608 if (r & D_REDRAWME) should_redraw = true;
4609
4610 if (should_redraw)
4611 {
4612 update_hw_screen();
4613 }
4614 }
4615
4616 break;
4617
4618 } // switch(obj)
4619
4620 redraw = 0;
4621
4622 update_hw_screen();
4623 // let other objects continue to animate
4624 broadcast_dialog_message(MSG_IDLE, 0);
4625 }
4626
4627 if(last_draw==1)
4628 {
4629 draw_arrow_button(screen, xx, yy, 16, bh, obj==top_btn, 0);
4630 }
4631 }
4632
4633 /* _handle_scrollable_scroll:
4634 * Helper function to scroll through a scrollable object.
4635 */
4636
4637 static void _handle_jwin_scrollable_scroll(DIALOG *d, int32_t listsize, int32_t *index, int32_t *offset, FONT *fnt)
4638 {
4639 int32_t height = (d->h-3) / text_height(fnt);
4640
4641 if(listsize <= 0)
4642 {
4643 *index = *offset = 0;
4644 return;
4645 }
4646
4647 // check selected item
4648 if(*index < 0)
4649 *index = 0;
4650 else if(*index >= listsize)
4651 *index = listsize - 1;
4652
4653 // check scroll position
4654 while((*offset > 0) && (*offset + height > listsize))
4655 (*offset)--;
4656
4657 if(*offset >= *index)
4658 {
4659 if(*index < 0)
4660 *offset = 0;
4661 else
4662 *offset = *index;
4663 }
4664 else
4665 {
4666 while((*offset + height - 1) < *index)
4667 (*offset)++;
4668 }
4669 }
4670
4671 /* idle_cb:
4672 * rest_callback() routine to keep dialogs animating nice and smoothly.
4673 */
4674
4675 static void idle_cb()
4676 {
4677 broadcast_dialog_message(MSG_IDLE, 0);
4678 }
4679
4680 /* _handle_listbox_click:
4681 * Helper to process a click on a listbox, doing hit-testing and moving
4682 * the selection.
4683 */
4684
4685 static bool _handle_jwin_listbox_click(DIALOG *d)
4686 {
4687 ListData *data = (ListData *)d->dp;
4688 char *sel = (char *)d->dp2;
4689 int32_t listsize, height;
4690 int32_t i, j;
4691
4692 data->listFunc(-1, &listsize);
4693
4694 if(!listsize)
4695 return false;
4696
4697 height = (d->h-3) / text_height(*data->font);
4698
4699 i = MID(0, ((gui_mouse_y() - d->y - 4) / text_height(*data->font)),
4700 ((d->h-3) / text_height(*data->font) - 1));
4701 i += d->d2;
4702
4703 if(i < d->d2)
4704 i = d->d2;
4705 else
4706 {
4707 if(i > d->d2 + height-1)
4708 i = d->d2 + height-1;
4709
4710 if(i >= listsize)
4711 i = listsize-1;
4712 }
4713
4714 if(gui_mouse_y() <= d->y)
4715 i = MAX(i-1, 0);
4716 else if(gui_mouse_y() >= d->y+d->h)
4717 i = MIN(i+1, listsize-1);
4718
4719 if(i != d->d1)
4720 {
4721 if(sel)
4722 {
4723 if(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG))
4724 {
4725 if((key_shifts & KB_SHIFT_FLAG) || (d->flags & D_INTERNAL))
4726 {
4727 for(j=MIN(i, d->d1); j<=MAX(i, d->d1); j++)
4728 sel[j] = TRUE;
4729 }
4730 else
4731 sel[i] = TRUE;
4732 }
4733 }
4734
4735 d->d1 = i;
4736 i = d->d2;
4737
4738 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
4739
4740 object_message(d, MSG_DRAW, 0);
4741
4742 if(i != d->d2)
4743 rest_callback(MID(10, text_height(font)*16-d->h, 100), idle_cb);
4744 return true;
4745 }
4746 return false;
4747 }
4748
4749 /* _jwin_draw_scrollable_frame:
4750 * Helper function to draw a frame for all objects with vertical scrollbars.
4751 */
4752 void _jwin_draw_scrollable_frame(DIALOG *d, int32_t listsize, int32_t offset, int32_t height, int32_t type)
4753 {
4754 int32_t pos, len;
4755 int32_t xx, yy, hh, bh;
4756 static BITMAP *pattern = NULL; // just create it once
4757
4758 /* draw frame */
4759 if(type)
4760 // for droplists
4761 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DARK);
4762 else
4763 jwin_draw_frame(screen, d->x, d->y, d->w, d->h, FR_DEEP);
4764
4765 /* possibly draw scrollbar */
4766 if(listsize > height)
4767 {
4768 _calc_scroll_bar(d->h, height, listsize, offset, &bh, &len, &pos);
4769
4770 xx = d->x + d->w - 18;
4771
4772 draw_arrow_button(screen, xx, d->y+2, 16, bh, 1, 0);
4773 draw_arrow_button(screen, xx, d->y+d->h-2-bh, 16, bh, 0, 0);
4774
4775 if(d->h > 32)
4776 {
4777 yy = d->y + 16;
4778 hh = (d->h-32);
4779
4780 /* create and draw the scrollbar */
4781 if(!pattern)
4782 pattern = create_bitmap_ex(bitmap_color_depth(screen),2,2);
4783
4784 putpixel(pattern, 0, 1, scheme[jcLIGHT]);
4785 putpixel(pattern, 1, 0, scheme[jcLIGHT]);
4786 putpixel(pattern, 0, 0, scheme[jcBOX]);
4787 putpixel(pattern, 1, 1, scheme[jcBOX]);
4788
4789 drawing_mode(DRAW_MODE_COPY_PATTERN, pattern, 0, 0);
4790 rectfill(screen, xx, yy, xx+15, yy+hh-1, 0);
4791 solid_mode();
4792
4793 if(d->h > 32+6)
4794 {
4795 jwin_draw_button(screen, xx, yy+pos, 16, len, 0, 1);
4796 }
4797 }
4798
4799 if(d->flags & D_GOTFOCUS)
4800 _dotted_rect(d->x+2, d->y+2, d->x+d->w-19, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4801 }
4802 else if(d->flags & D_GOTFOCUS)
4803 _dotted_rect(d->x+2, d->y+2, d->x+d->w-3, d->y+d->h-3, scheme[jcTEXTFG], scheme[jcTEXTBG]);
4804 }
4805
4806 /*
4807 Effectively an overload of _jwin_draw_listbox that is used eclusively for file/abc listers.
4808 */
4809 void _jwin_draw_abclistbox(DIALOG *d)
4810 {
4811 int32_t height, listsize, i, len, bar, x, y, w;
4812 int32_t fg_color, bg_color, fg, bg;
4813 char *sel = (char*)d->dp2;
4814 char s[1024] = { 0 };
4815 ListData *data = (ListData *)d->dp;
4816
4817 FONT* oldfont = font;
4818 font = *data->font;
4819
4820 data->listFunc(-1, &listsize);
4821 height = (d->h-3) / text_height(font);
4822 bar = (listsize > height);
4823 w = (bar ? d->w-21 : d->w-5);
4824 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h+9, scheme[jcBOX]);
4825 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4826 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4827
4828 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4829 _allegro_vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4830 _allegro_vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4831 _allegro_vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4832 _allegro_vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4833 //al_trace("Drawing %s\n", abc_keypresses);
4834 {
4835 rectfill(screen, d->x+1, d->y+d->h+2, d->x+d->w-2, d->y+1+d->h+text_height(font), bg_color);
4836 strncpy(s, abc_keypresses, 1023);
4837 char* s2 = s;
4838 int32_t tw = (d->w-1);
4839 while(text_length(font, s2) >= tw)
4840 {
4841 ++s2;
4842 }
4843 textout_ex(screen, font, s2, d->x+1, d->y+d->h+2,fg_color, bg_color);
4844 }
4845 //d->flags|=D_DIRTY;
4846
4847 /* draw box contents */
4848 for(i=0; i<height; i++)
4849 {
4850 if(d->d2+i < listsize)
4851 {
4852 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4853 {
4854 fg = scheme[jcSELFG];
4855 bg = scheme[jcSELBG];
4856 }
4857 else if((sel) && (sel[d->d2+i]))
4858 {
4859 fg = scheme[jcDISABLED_FG];
4860 bg = scheme[jcSELBG];
4861 }
4862 else
4863 {
4864 fg = fg_color;
4865 bg = bg_color;
4866 }
4867
4868 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4869 x = d->x + 4;
4870 y = d->y + 4 + i*text_height(*data->font);
4871 // text_mode(bg);
4872 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4873 x += 8;
4874 len = (int32_t)strlen(s);
4875
4876 while(text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4877 {
4878 len--;
4879 s[len] = 0;
4880 }
4881
4882 textout_ex(screen, *data->font, s, x, y, fg,bg);
4883 x += text_length(*data->font, s);
4884
4885 if(x <= d->x+w)
4886 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4887 }
4888 else
4889 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4890 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4891 }
4892
4893 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4894 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4895 d->x+w+2, d->y+d->h-3, bg_color);
4896
4897 /* draw frame, maybe with scrollbar */
4898 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4899
4900 font = oldfont;
4901 }
4902
4903 /* _jwin_draw_listbox:
4904 * Helper function to draw a listbox object.
4905 */
4906 void _jwin_draw_listbox(DIALOG *d)
4907 {
4908 int32_t height, listsize, i, len, bar, x, y, w;
4909 int32_t fg_color, bg_color, fg, bg;
4910 char *sel = (char*)d->dp2;
4911 char s[1024] = {0};
4912 ListData *data = (ListData *)d->dp;
4913
4914 data->listFunc(-1, &listsize);
4915 height = (d->h-3) / text_height(*data->font);
4916 bar = (listsize > height);
4917 w = (bar ? d->w-21 : d->w-5);
4918 fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : (d->fg ? d->fg : scheme[jcTEXTFG]);
4919 bg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_BG] : (d->bg ? d->bg : scheme[jcTEXTBG]);
4920
4921 rectfill(screen, d->x+2, d->y+2, d->x+w+2, d->y+3, bg_color);
4922 _allegro_vline(screen, d->x+2, d->y+4, d->y+d->h-3, bg_color);
4923 _allegro_vline(screen, d->x+3, d->y+4, d->y+d->h-3, bg_color);
4924 _allegro_vline(screen, d->x+w+1, d->y+4, d->y+d->h-3, bg_color);
4925 _allegro_vline(screen, d->x+w+2, d->y+4, d->y+d->h-3, bg_color);
4926 //al_trace("Drawing %s\n", abc_keypresses);
4927 //d->flags|=D_DIRTY;
4928
4929 /* draw box contents */
4930 for(i=0; i<height; i++)
4931 {
4932 if(d->d2+i < listsize)
4933 {
4934 if(d->d2+i == d->d1 && !(d->flags & D_DISABLED))
4935 {
4936 fg = scheme[jcSELFG];
4937 bg = scheme[jcSELBG];
4938 }
4939 else if((sel) && (sel[d->d2+i]))
4940 {
4941 fg = scheme[jcMEDDARK];
4942 bg = scheme[jcSELBG];
4943 }
4944 else
4945 {
4946 fg = fg_color;
4947 bg = bg_color;
4948 }
4949
4950 strncpy(s, data->listFunc(i+d->d2, NULL), 1023);
4951 x = d->x + 4;
4952 y = d->y + 4 + i*text_height(*data->font);
4953 // text_mode(bg);
4954 rectfill(screen, x, y, x+7, y+text_height(*data->font)-1, bg);
4955 x += 8;
4956 len = (int32_t)strlen(s);
4957
4958 while(len > 0 && text_length(*data->font, s) >= d->w - (bar ? 26 : 10))
4959 {
4960 len--;
4961 s[len] = 0;
4962 }
4963
4964 textout_ex(screen, *data->font, s, x, y, fg,bg);
4965 x += text_length(*data->font, s);
4966
4967 if(x <= d->x+w)
4968 rectfill(screen, x, y, d->x+w, y+text_height(*data->font)-1, bg);
4969 }
4970 else
4971 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4972 d->x+w+2, d->y+3+(i+1)*text_height(*data->font), bg_color);
4973 }
4974
4975 if(d->y+4+i*text_height(font) <= d->y+d->h-3)
4976 rectfill(screen, d->x+2, d->y+4+i*text_height(*data->font),
4977 d->x+w+2, d->y+d->h-3, bg_color);
4978
4979 /* draw frame, maybe with scrollbar */
4980 _jwin_draw_scrollable_frame(d, listsize, d->d2, height, (d->flags&D_USER)?1:0);
4981 }
4982
4983 /* jwin_list_proc:
4984 * A list box object. The dp field points to a ListData struct containing
4985 * a function which it will call
4986 * to obtain information about the list. This should follow the form:
4987 * char *<list_func_name> (int32_t index, int32_t *list_size);
4988 * If index is zero or positive, the function should return a pointer to
4989 * the string which is to be displayed at position index in the list. If
4990 * index is negative, it should return null and list_size should be set
4991 * to the number of items in the list. The list box object will allow the
4992 * user to scroll through the list and to select items list by clicking
4993 * on them, and if it has the input focus also by using the arrow keys. If
4994 * the D_EXIT flag is set, double clicking on a list item will cause it to
4995 * close the dialog. The index of the selected item is held in the d1
4996 * field, and d2 is used to store how far it has scrolled through the list.
4997 */
4998 int32_t jwin_list_proc(int32_t msg, DIALOG *d, int32_t c)
4999 {
5000 ListData *data = (ListData *)d->dp;
5001 int32_t listsize, i, bottom, height, bar, orig;
5002 char *sel = (char *)d->dp2;
5003 int32_t redraw = FALSE;
5004
5005 switch(msg)
5006 {
5007
5008 case MSG_START:
5009 data->listFunc(-1, &listsize);
5010 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5011 break;
5012
5013 case MSG_DRAW:
5014 _jwin_draw_listbox(d);
5015 break;
5016
5017 case MSG_CLICK:
5018 data->listFunc(-1, &listsize);
5019 height = (d->h-3) / text_height(*data->font);
5020 bar = (listsize > height);
5021
5022 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5023 {
5024 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5025 {
5026 for(i=0; i<listsize; i++)
5027 {
5028 if(sel[i])
5029 {
5030 redraw = TRUE;
5031 sel[i] = FALSE;
5032 }
5033 }
5034
5035 if(redraw)
5036 {
5037 object_message(d, MSG_DRAW, 0);
5038 }
5039 }
5040
5041 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5042
5043 bool rightClicked=(gui_mouse_b()&2)!=0;
5044 while(gui_mouse_b())
5045 {
5046 broadcast_dialog_message(MSG_IDLE, 0);
5047 d->flags |= D_INTERNAL;
5048 bool should_redraw = false;
5049 if(_handle_jwin_listbox_click(d))
5050 {
5051 d->flags &= ~D_INTERNAL;
5052 GUI_EVENT(d, geCHANGE_SELECTION);
5053 should_redraw = true;
5054 }
5055 d->flags &= ~D_INTERNAL;
5056
5057 /* let other objects continue to animate */
5058 int r = broadcast_dialog_message(MSG_IDLE, 0);
5059 if (r & D_REDRAWME) should_redraw = true;
5060
5061 if (should_redraw)
5062 {
5063 update_hw_screen();
5064 }
5065 }
5066
5067 if(rightClicked)
5068 {
5069 GUI_EVENT(d, geRCLICK);
5070 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5071 {
5072 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5073 funcType func=reinterpret_cast<funcType>(d->dp3);
5074 func(d->d1, gui_mouse_x(), gui_mouse_y());
5075 }
5076 }
5077
5078 if(d->flags & D_USER)
5079 {
5080 if(listsize)
5081 {
5082 clear_keybuf();
5083 return D_CLOSE;
5084 }
5085 }
5086
5087 return D_REDRAWME;
5088 }
5089 else
5090 {
5091 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5092 }
5093
5094 break;
5095
5096 case MSG_DCLICK:
5097 // Ignore double right-click
5098 if((gui_mouse_b()&2)!=0)
5099 break;
5100
5101 data->listFunc(-1, &listsize);
5102 height = (d->h-3) / text_height(*data->font);
5103 bar = (listsize > height);
5104
5105 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5106 {
5107 if(listsize)
5108 {
5109 i = d->d1;
5110 object_message(d, MSG_CLICK, 0);
5111
5112 if(i == d->d1)
5113 {
5114 if(d->flags & D_EXIT)
5115 return D_CLOSE;
5116 else GUI_EVENT(d, geDCLICK);
5117 }
5118 }
5119 }
5120
5121 break;
5122
5123 case MSG_KEY:
5124 data->listFunc(-1, &listsize);
5125
5126 if((listsize) && (d->flags & D_EXIT))
5127 return D_CLOSE;
5128
5129 break;
5130
5131 case MSG_WANTFOCUS:
5132 return D_WANTFOCUS;
5133
5134 case MSG_WANTWHEEL:
5135 return 1;
5136
5137 case MSG_WHEEL:
5138 data->listFunc(-1, &listsize);
5139 height = (d->h-4) / text_height(*data->font);
5140
5141 if(height < listsize)
5142 {
5143 int32_t delta = (height > 3) ? 3 : 1;
5144
5145 if(c > 0)
5146 {
5147 i = MAX(0, d->d2-delta);
5148 }
5149 else
5150 {
5151 i = MIN(listsize-height, d->d2+delta);
5152 }
5153
5154 if(i != d->d2)
5155 {
5156 d->d2 = i;
5157 object_message(d, MSG_DRAW, 0);
5158 GUI_EVENT(d, geCHANGE_SELECTION);
5159 return D_REDRAWME;
5160 }
5161 }
5162
5163 break;
5164
5165 case MSG_CHAR:
5166 data->listFunc(-1,&listsize);
5167
5168 if(listsize)
5169 {
5170 c >>= 8;
5171
5172 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5173
5174 if(bottom >= listsize-1)
5175 bottom = listsize-1;
5176
5177 orig = d->d1;
5178
5179 if(c == KEY_UP)
5180 d->d1--;
5181 else if(c == KEY_DOWN)
5182 d->d1++;
5183 else if(c == KEY_HOME)
5184 d->d1 = 0;
5185 else if(c == KEY_END)
5186 d->d1 = listsize-1;
5187 else if(c == KEY_PGUP)
5188 {
5189 if(d->d1 > d->d2)
5190 d->d1 = d->d2;
5191 else
5192 d->d1 -= (bottom - d->d2);
5193 }
5194 else if(c == KEY_PGDN)
5195 {
5196 if(d->d1 < bottom)
5197 d->d1 = bottom;
5198 else
5199 d->d1 += (bottom - d->d2);
5200 }
5201 else
5202 return D_O_K;
5203
5204 if(sel)
5205 {
5206 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5207 {
5208 for(i=0; i<listsize; i++)
5209 sel[i] = FALSE;
5210 }
5211 else if(key_shifts & KB_SHIFT_FLAG)
5212 {
5213 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5214 {
5215 if(key_shifts & KB_CTRL_FLAG)
5216 sel[i] = (i != d->d1);
5217 else
5218 sel[i] = TRUE;
5219 }
5220 }
5221 }
5222
5223 /* if we changed something, better redraw... !Also bounds the index! */
5224 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5225
5226 GUI_EVENT(d, geCHANGE_SELECTION);
5227
5228 if (d->d1 != orig)
5229 d->flags |= D_DIRTY;
5230 return D_USED_CHAR;
5231 }
5232
5233 break;
5234 }
5235
5236 return D_O_K;
5237 }
5238
5239
5240 /*
5241 Effectively an overload of jwin_list_proc that i used eclusively for abc lists.
5242 This calls the appropriate form of drawing for those listers.
5243 */
5244 int32_t jwin_do_abclist_proc(int32_t msg, DIALOG *d, int32_t c)
5245 {
5246 ListData *data = (ListData *)d->dp;
5247 int32_t listsize, i, bottom, height, bar, orig, h;
5248 int32_t ret = D_O_K;
5249 bool revert_size = false;
5250 if((d->flags & D_RESIZED) == 0)
5251 {
5252 h = d->h;
5253 d->h -= text_height(*data->font);
5254 d->flags |= D_RESIZED;
5255 revert_size = true;
5256 }
5257 char *sel = (char *)d->dp2;
5258 int32_t redraw = FALSE;
5259
5260 switch(msg)
5261 {
5262
5263 case MSG_START:
5264 data->listFunc(-1, &listsize);
5265 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5266 break;
5267
5268 case MSG_DRAW:
5269 _jwin_draw_abclistbox(d);
5270 break;
5271
5272 case MSG_CLICK:
5273 if(gui_mouse_y() > (d->y+d->h-1))
5274 {
5275 if(gui_mouse_y() > (d->y+d->h+2))
5276 {
5277 //Clicked on the box displaying the patternmatch
5278 }
5279 else {} //Clicked between the lister and patternmatch
5280 }
5281 else //Clicked the lister
5282 {
5283 data->listFunc(-1, &listsize);
5284 height = (d->h-3) / text_height(*data->font);
5285 bar = (listsize > height);
5286
5287 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5288 {
5289 if((sel) && (!(key_shifts & KB_CTRL_FLAG)))
5290 {
5291 for(i=0; i<listsize; i++)
5292 {
5293 if(sel[i])
5294 {
5295 redraw = TRUE;
5296 sel[i] = FALSE;
5297 }
5298 }
5299
5300 if(redraw)
5301 {
5302 object_message(d, MSG_DRAW, 0);
5303 }
5304 }
5305
5306 if(_handle_jwin_listbox_click(d)) GUI_EVENT(d, geCHANGE_SELECTION);
5307
5308 bool rightClicked=(gui_mouse_b()&2)!=0;
5309 while(gui_mouse_b())
5310 {
5311 broadcast_dialog_message(MSG_IDLE, 0);
5312 d->flags |= D_INTERNAL;
5313 if(_handle_jwin_listbox_click(d))
5314 {
5315 d->flags &= ~D_INTERNAL;
5316 GUI_EVENT(d, geCHANGE_SELECTION);
5317 update_hw_screen();
5318 }
5319 d->flags &= ~D_INTERNAL;
5320 rest(1);
5321 }
5322
5323 if(rightClicked)
5324 {
5325 GUI_EVENT(d, geRCLICK);
5326 if((d->flags&(D_USER<<1))!=0 && d->dp3)
5327 {
5328 typedef void (*funcType)(int32_t /* index */, int32_t /* x */, int32_t /* y */);
5329 funcType func=reinterpret_cast<funcType>(d->dp3);
5330 func(d->d1, gui_mouse_x(), gui_mouse_y());
5331 }
5332 }
5333
5334 if(d->flags & D_USER)
5335 {
5336 if(listsize)
5337 {
5338 clear_keybuf();
5339 ret = D_CLOSE;
5340 }
5341 }
5342
5343 return D_REDRAWME;
5344 }
5345 else
5346 {
5347 _handle_jwin_scrollable_scroll_click(d, listsize, &d->d2, *data->font);
5348 }
5349 }
5350 break;
5351
5352 case MSG_DCLICK:
5353 // Ignore double right-click
5354 if((gui_mouse_b()&2)!=0)
5355 break;
5356
5357 if(gui_mouse_y() > (d->y+d->h-1))
5358 {
5359 if(gui_mouse_y() > (d->y+d->h+2))
5360 {
5361 //Clicked on the box displaying the patternmatch
5362 }
5363 else {} //Clicked between the lister and patternmatch
5364 }
5365 else //Clicked the lister
5366 {
5367 data->listFunc(-1, &listsize);
5368 height = (d->h-3) / text_height(*data->font);
5369 bar = (listsize > height);
5370
5371 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5372 {
5373 if(listsize)
5374 {
5375 i = d->d1;
5376 object_message(d, MSG_CLICK, 0);
5377
5378 if(i == d->d1)
5379 {
5380 if(d->flags & D_EXIT)
5381 ret = D_CLOSE;
5382 else GUI_EVENT(d, geDCLICK);
5383 }
5384 }
5385 }
5386 }
5387 break;
5388
5389 case MSG_KEY:
5390 data->listFunc(-1, &listsize);
5391
5392 if((listsize) && (d->flags & D_EXIT))
5393 ret = D_CLOSE;
5394
5395 break;
5396
5397 case MSG_WANTFOCUS:
5398 ret = D_WANTFOCUS;
5399 break;
5400
5401 case MSG_WANTWHEEL:
5402 return 1;
5403
5404 case MSG_WHEEL:
5405 data->listFunc(-1, &listsize);
5406 height = (d->h-4) / text_height(*data->font);
5407
5408 if(height < listsize)
5409 {
5410 int32_t delta = (height > 3) ? 3 : 1;
5411
5412 if(c > 0)
5413 {
5414 i = MAX(0, d->d2-delta);
5415 }
5416 else
5417 {
5418 i = MIN(listsize-height, d->d2+delta);
5419 }
5420
5421 if(i != d->d2)
5422 {
5423 d->d2 = i;
5424 object_message(d, MSG_DRAW, 0);
5425 GUI_EVENT(d, geCHANGE_SELECTION);
5426 ret |= D_REDRAWME;
5427 }
5428 }
5429
5430 break;
5431
5432 case MSG_CHAR:
5433 data->listFunc(-1,&listsize);
5434
5435 if(listsize)
5436 {
5437 c >>= 8;
5438
5439 bottom = d->d2 + (d->h-3)/text_height(*data->font) - 1;
5440
5441 if(bottom >= listsize-1)
5442 bottom = listsize-1;
5443
5444 orig = d->d1;
5445
5446 if(c == KEY_UP)
5447 d->d1--;
5448 else if(c == KEY_DOWN)
5449 d->d1++;
5450 else if(c == KEY_HOME)
5451 d->d1 = 0;
5452 else if(c == KEY_END)
5453 d->d1 = listsize-1;
5454 else if(c == KEY_PGUP)
5455 {
5456 if(d->d1 > d->d2)
5457 d->d1 = d->d2;
5458 else
5459 d->d1 -= (bottom - d->d2);
5460 }
5461 else if(c == KEY_PGDN)
5462 {
5463 if(d->d1 < bottom)
5464 d->d1 = bottom;
5465 else
5466 d->d1 += (bottom - d->d2);
5467 }
5468 else
5469 break; //return D_O_K;
5470
5471 if(sel)
5472 {
5473 if(!(key_shifts & (KB_SHIFT_FLAG | KB_CTRL_FLAG)))
5474 {
5475 for(i=0; i<listsize; i++)
5476 sel[i] = FALSE;
5477 }
5478 else if(key_shifts & KB_SHIFT_FLAG)
5479 {
5480 for(i=MIN(orig, d->d1); i<=MAX(orig, d->d1); i++)
5481 {
5482 if(key_shifts & KB_CTRL_FLAG)
5483 sel[i] = (i != d->d1);
5484 else
5485 sel[i] = TRUE;
5486 }
5487 }
5488 }
5489
5490 /* if we changed something, better redraw... */
5491 _handle_jwin_scrollable_scroll(d, listsize, &d->d1, &d->d2, *data->font);
5492
5493 GUI_EVENT(d, geCHANGE_SELECTION);
5494
5495 if (d->d1 != orig)
5496 d->flags |= D_DIRTY;
5497 ret = D_USED_CHAR;
5498 }
5499
5500 break;
5501 }
5502 if(revert_size)
5503 {
5504 d->h = h;
5505 d->flags &= ~D_RESIZED;
5506 }
5507 return ret;
5508 }
5509
5510 /* _jwin_draw_textbox:
5511 * Helper function to draw a textbox object.
5512 */
5513 void _jwin_draw_textbox(char *thetext, int32_t *listsize, int32_t draw, int32_t offset,
5514 int32_t wword, int32_t tabsize, int32_t x, int32_t y, int32_t w, int32_t h,
5515 int32_t disabled)
5516 {
5517 int32_t fg = scheme[jcTEXTFG];
5518 int32_t bg = scheme[jcTEXTBG];
5519 int32_t y1 = y+4;
5520 int32_t x1;
5521 int32_t len;
5522 int32_t ww = w-10;
5523 char s[16] = {0};
5524 char text[16] = {0};
5525 char space[16] = {0};
5526 char *printed = text;
5527 char *scanned = text;
5528 char *oldscan = text;
5529 char *ignore = NULL;
5530 char *tmp, *ptmp;
5531 int32_t width;
5532 int32_t line = 0;
5533 int32_t i = 0;
5534 int32_t noignore;
5535 // int32_t rtm;
5536
5537 usetc(s+usetc(s, '.'), 0);
5538 usetc(text+usetc(text, ' '), 0);
5539 usetc(space+usetc(space, ' '), 0);
5540
5541 /* find the correct text */
5542 if(thetext != NULL)
5543 {
5544 printed = thetext;
5545 scanned = thetext;
5546 }
5547
5548 /* choose the text color */
5549 if(disabled)
5550 {
5551 fg = scheme[jcDISABLED_FG];
5552 bg = scheme[jcDISABLED_BG];
5553 }
5554
5555 /* do some drawing setup */
5556 if(draw)
5557 {
5558 /* initial start blanking at the top */
5559 rectfill(screen, x+2, y+2, x+w-2, y1-1, bg);
5560 }
5561
5562 // rtm = text_mode(bg);
5563
5564 /* loop over the entire string */
5565 for(;;)
5566 {
5567 width = 0;
5568
5569 /* find the next break */
5570 while(ugetc(scanned))
5571 {
5572 /* check for a forced break */
5573 if(ugetc(scanned) == '\n')
5574 {
5575 scanned += uwidth(scanned);
5576
5577 /* we are done parsing the line end */
5578 break;
5579 }
5580
5581 /* the next character length */
5582 usetc(s+usetc(s, ugetc(scanned)), 0);
5583 len = text_length(font, s);
5584
5585 /* modify length if its a tab */
5586 if(ugetc(s) == '\t')
5587 len = tabsize * text_length(font, space);
5588
5589 /* check for the end of a line by excess width of next char */
5590 if(width+len >= ww)
5591 {
5592 /* we have reached end of line do we go back to find start */
5593 if(wword)
5594 {
5595 /* remember where we were */
5596 oldscan = scanned;
5597 noignore = FALSE;
5598
5599 /* go backwards looking for start of word */
5600 while(!uisspace(ugetc(scanned)))
5601 {
5602 /* don't wrap too far */
5603 if(scanned == printed)
5604 {
5605 /* the whole line is filled, so stop here */
5606 tmp = ptmp = scanned;
5607
5608 while(ptmp != oldscan)
5609 {
5610 ptmp = tmp;
5611 tmp += uwidth(tmp);
5612 }
5613
5614 scanned = ptmp;
5615 noignore = TRUE;
5616 break;
5617 }
5618
5619 /* look further backwards to wrap */
5620 tmp = ptmp = printed;
5621
5622 while(tmp < scanned)
5623 {
5624 ptmp = tmp;
5625 tmp += uwidth(tmp);
5626 }
5627
5628 scanned = ptmp;
5629 }
5630
5631 /* put the space at the end of the line */
5632 if(!noignore)
5633 {
5634 ignore = scanned;
5635 scanned += uwidth(scanned);
5636 }
5637 else
5638 ignore = NULL;
5639
5640 /* check for endline at the convenient place */
5641 if(ugetc(scanned) == '\n')
5642 scanned += uwidth(scanned);
5643 }
5644
5645 /* we are done parsing the line end */
5646 break;
5647 }
5648
5649 /* the character can be added */
5650 scanned += uwidth(scanned);
5651 width += len;
5652 }
5653
5654 /* check if we are to print it */
5655 if((draw) && (line >= offset) && (y1+text_height(font) < (y+h-3)))
5656 {
5657 x1 = x+4;
5658
5659 /* the initial blank bit */
5660 rectfill(screen, x+2, y1, x1-1, y1+text_height(font), bg);
5661
5662 /* print up to the marked character */
5663 while(printed != scanned)
5664 {
5665 /* do special stuff for each character */
5666 switch(ugetc(printed))
5667 {
5668
5669 case '\r':
5670 case '\n':
5671 /* don't print endlines in the text */
5672 break;
5673
5674 /* possibly expand the tabs */
5675 case '\t':
5676 for(i=0; i<tabsize; i++)
5677 {
5678 usetc(s+usetc(s, ' '), 0);
5679 textout_ex(screen, font, s, x1, y1, fg,bg);
5680 x1 += text_length(font, s);
5681 }
5682
5683 break;
5684
5685 /* print a normal character */
5686 default:
5687 if(printed != ignore)
5688 {
5689 usetc(s+usetc(s, ugetc(printed)), 0);
5690 textout_ex(screen, font, s, x1, y1, fg,bg);
5691 x1 += text_length(font, s);
5692 }
5693 }
5694
5695 /* goto the next character */
5696 printed += uwidth(printed);
5697 }
5698
5699 /* the last blank bit */
5700 if(x1 <= x+w-3)
5701 rectfill(screen, x1, y1, x+w-2, y1+text_height(font)-1, bg);
5702
5703 /* print the line end */
5704 y1 += text_height(font);
5705 }
5706
5707 printed = scanned;
5708
5709 /* we have done a line */
5710 line++;
5711
5712 /* check if we are at the end of the string */
5713 if(!ugetc(printed))
5714 {
5715 /* the under blank bit */
5716 if(draw)
5717 rectfill(screen, x+1, y1, x+w-2, y+h-1, bg);
5718
5719 /* tell how many lines we found */
5720 *listsize = line;
5721 // text_mode(rtm);
5722 return;
5723 }
5724 }
5725
5726 // text_mode(rtm);
5727 }
5728
5729 /* jwin_textbox_proc:
5730 * A text box object. The dp field points to a char * which is the text
5731 * to be displayed in the text box. If the text is long, there will be
5732 * a vertical scrollbar on the right hand side of the object which can
5733 * be used to scroll through the text. The default is to print the text
5734 * with word wrapping, but if the D_SELECTED flag is set, the text will
5735 * be printed with character wrapping. The d1 field is used internally
5736 * to store the number of lines of text, and d2 is used to store how far
5737 * it has scrolled through the text.
5738 */
5739 int32_t jwin_textbox_proc(int32_t msg, DIALOG *d, int32_t c)
5740 {
5741 int32_t height, bar, ret = D_O_K;
5742 int32_t start, top, bottom,l;
5743 int32_t used, delta;
5744 // int32_t fg_color = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
5745
5746 FONT *oldfont=NULL;
5747
5748 if(d->dp2!=NULL)
5749 {
5750 oldfont=font;
5751 font=(FONT*)d->dp2;
5752 }
5753
5754 /* calculate the actual height */
5755 height = (d->h-4) / text_height(font);
5756
5757 switch(msg)
5758 {
5759
5760 case MSG_START:
5761 /* measure how many lines of text we contain */
5762 _jwin_draw_textbox((char*)d->dp, &d->d1,
5763 0, /* DONT DRAW anything */
5764 d->d2, !(d->flags & D_SELECTED), 8,
5765 d->x, d->y, d->w, d->h,
5766 (d->flags & D_DISABLED));
5767 break;
5768
5769 case MSG_DRAW:
5770 /* tell the object to sort of draw, but only calculate the listsize */
5771 _jwin_draw_textbox((char*)d->dp, &d->d1,
5772 0, /* DONT DRAW anything */
5773 d->d2, !(d->flags & D_SELECTED), 8,
5774 d->x, d->y, d->w, d->h,
5775 (d->flags & D_DISABLED));
5776
5777 if(d->d1 > height)
5778 {
5779 bar = 16;
5780 }
5781 else
5782 {
5783 bar = 0;
5784 d->d2 = 0;
5785 }
5786
5787 /* now do the actual drawing */
5788 _jwin_draw_textbox((char*)d->dp, &d->d1, 1, d->d2,
5789 !(d->flags & D_SELECTED), 8,
5790 d->x, d->y, d->w-bar-1, d->h,
5791 (d->flags & D_DISABLED));
5792
5793 /* draw the frame around */
5794 _jwin_draw_scrollable_frame(d, d->d1, d->d2, height, 0);
5795 break;
5796
5797 case MSG_CLICK:
5798 /* figure out if it's on the text or the scrollbar */
5799 bar = (d->d1 > height);
5800
5801 if((!bar) || (gui_mouse_x() < d->x+d->w-18))
5802 {
5803 /* clicked on the text area */
5804 ret = D_O_K;
5805 }
5806 else
5807 {
5808 /* clicked on the scroll area */
5809 _handle_jwin_scrollable_scroll_click(d, d->d1, &d->d2, font);
5810 }
5811
5812 break;
5813
5814 case MSG_WANTWHEEL:
5815 return 1;
5816
5817 case MSG_WHEEL:
5818 l = (d->h-8)/text_height(font);
5819 delta = (l > 3) ? 3 : 1;
5820
5821 // scroll, making sure that the list stays in bounds
5822 start = d->d2;
5823 d->d2 = (c > 0) ? MAX(0, d->d2-delta) : MIN(d->d1-l, d->d2+delta);
5824
5825 // if we changed something, better redraw...
5826 if(d->d2 != start)
5827 {
5828 d->flags |= D_DIRTY;
5829 }
5830
5831 ret = D_O_K;
5832 break;
5833
5834 case MSG_CHAR:
5835 start = d->d2;
5836 used = D_USED_CHAR;
5837
5838 if(d->d1 > 0)
5839 {
5840 if(d->d2 > 0)
5841 top = d->d2+1;
5842 else
5843 top = 0;
5844
5845 l = (d->h-3)/text_height(font);
5846
5847 bottom = d->d2 + l - 1;
5848
5849 if(bottom >= d->d1-1)
5850 bottom = d->d1-1;
5851 else
5852 bottom--;
5853
5854 if((c>>8) == KEY_UP)
5855 d->d2--;
5856 else if((c>>8) == KEY_DOWN)
5857 d->d2++;
5858 else if((c>>8) == KEY_HOME)
5859 d->d2 = 0;
5860 else if((c>>8) == KEY_END)
5861 d->d2 = d->d1-l;
5862 else if((c>>8) == KEY_PGUP)
5863 d->d2 = d->d2-(bottom-top);
5864 else if((c>>8) == KEY_PGDN)
5865 d->d2 = d->d2+(bottom-top);
5866 else
5867 used = D_O_K;
5868
5869 /* make sure that the list stays in bounds */
5870 if(d->d2 > d->d1-l)
5871 d->d2 = d->d1-l;
5872
5873 if(d->d2 < 0)
5874 d->d2 = 0;
5875 }
5876 else
5877 used = D_O_K;
5878
5879 /* if we changed something, better redraw... */
5880 if(d->d2 != start)
5881 {
5882 d->proc(MSG_DRAW, d, 0);
5883 }
5884
5885 ret = used;
5886 break;
5887
5888 case MSG_WANTFOCUS:
5889
5890 /* if we don't have a scrollbar we can't do anything with the focus */
5891 if(d->d1 > height)
5892 ret = D_WANTFOCUS;
5893
5894 break;
5895
5896 default:
5897 ret = D_O_K;
5898 }
5899
5900 if(d->dp2!=NULL)
5901 {
5902 font=oldfont;
5903 }
5904
5905 return ret;
5906 }
5907
5908 /* jwin_slider_proc:
5909 * A slider control object. This object returns a value in d2, in the
5910 * range from 0 to d1. It will display as a vertical slider if h is
5911 * greater than or equal to w; otherwise, it will display as a horizontal
5912 * slider. dp can contain an optional bitmap to use for the slider handle;
5913 * dp2 can contain an optional callback function, which is called each
5914 * time d2 changes. The callback function should have the following
5915 * prototype:
5916 *
5917 * int32_t function(void *dp3, int32_t d2);
5918 *
5919 * The d_slider_proc object will return the value of the callback function.
5920 */
5921 int32_t jwin_slider_proc(int32_t msg, DIALOG *d, int32_t c)
5922 {
5923 BITMAP *slhan = NULL;
5924 int32_t sfg; /* slider foreground color */
5925 int32_t vert = TRUE; /* flag: is slider vertical? */
5926 int32_t hh = 7; /* handle height (width for horizontal sliders) */
5927 int32_t hmar; /* handle margin */
5928 int32_t slp; /* slider position */
5929 int32_t irange;
5930 int32_t slx, sly, slh, slw;
5931 fixed slratio, slmax, slpos;
5932 ASSERT(d);
5933
5934 /* check for slider direction */
5935 if(d->h < d->w)
5936 {
5937 vert = FALSE;
5938 }
5939
5940 /* set up the metrics for the control */
5941 if(d->dp != NULL)
5942 {
5943 slhan = (BITMAP *)d->dp;
5944
5945 if(vert)
5946 {
5947 hh = slhan->h;
5948 }
5949 else
5950 {
5951 hh = slhan->w;
5952 }
5953 }
5954
5955 hmar = hh/2;
5956 irange = (vert) ? d->h : d->w;
5957 slmax = itofix(irange-hh);
5958 slratio = slmax / (d->d1);
5959 slpos = slratio * d->d2;
5960 slp = fixtoi(slpos);
5961
5962 switch(msg)
5963 {
5964 case MSG_DRAW:
5965 // sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
5966 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : scheme[jcBOXFG];
5967
5968 if(vert)
5969 {
5970 rectfill(screen, d->x, d->y, d->x+d->w/2-2, d->y+d->h, scheme[jcBOX]);
5971 rectfill(screen, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h, sfg);
5972 rectfill(screen, d->x+d->w/2+2, d->y, d->x+d->w, d->y+d->h, scheme[jcBOX]);
5973 }
5974 else
5975 {
5976 rectfill(screen, d->x, d->y, d->x+d->w, d->y+d->h/2-2, scheme[jcBOX]);
5977 rectfill(screen, d->x, d->y+d->h/2-1, d->x+d->w, d->y+d->h/2+1, sfg);
5978 rectfill(screen, d->x, d->y+d->h/2+2, d->x+d->w, d->y+d->h, scheme[jcBOX]);
5979 }
5980
5981 if(d->flags & D_GOTFOCUS)
5982 {
5983 _dotted_rect(d->x, d->y, d->x+d->w, d->y+d->h, sfg, scheme[jcBOX]);
5984 }
5985
5986 /* okay, background and slot are drawn, now draw the handle */
5987 if(slhan)
5988 {
5989 if(vert)
5990 {
5991 slx = d->x+(d->w/2)-(slhan->w/2);
5992 sly = d->y+d->h-(hh+slp);
5993 }
5994 else
5995 {
5996 slx = d->x+slp;
5997 sly = d->y+(d->h/2)-(slhan->h/2);
5998 }
5999
6000 draw_sprite(screen, slhan, slx, sly);
6001 }
6002 else
6003 {
6004 /* draw default handle */
6005 if(vert)
6006 {
6007 slx = d->x;
6008 sly = d->y+d->h-(hh+slp);
6009 slw = d->w;
6010 slh = hh;
6011 }
6012 else
6013 {
6014 slx = d->x+slp;
6015 sly = d->y;
6016 slw = hh;
6017 slh = d->h;
6018 }
6019
6020 jwin_draw_button(screen, slx, sly, slw+1, slh+1, d->flags&D_DISABLED?3:0, 0);
6021 }
6022
6023 break;
6024
6025 default:
6026 return d_jslider_proc(msg, d, c);
6027 }
6028
6029 return D_O_K;
6030 }
6031
6032 const char* rowpref(int32_t row, bool alt)
6033 {
6034 static const char *lcol = "Level Colors", *syscol = "System Colors", *bosscol = "Boss Colors", *thmcol = "Theme Colors", *nlcol="";
6035 switch(row)
6036 {
6037 case 2: case 3: case 4: case 9:
6038 return lcol;
6039 case 14:
6040 return alt ? syscol : bosscol;
6041 case 15:
6042 return thmcol;
6043 default:
6044 return nlcol;
6045 }
6046 }
6047
6048 byte getHighlightColor(int32_t c)
6049 {
6050 RGB col;
6051 get_color(c, &col);
6052 return getHighlightColor(col);
6053 }
6054
6055 byte getHighlightColor(RGB const& col)
6056 {
6057 double lum = (pow(col.r/64.0, 2.2) * 0.2126) +
6058 (pow(col.g/64.0, 2.2) * 0.7152) +
6059 (pow(col.b/64.0, 2.2) * 0.0722);
6060 return lum < 0.4 ? vc(15) : vc(0);
6061 //Old -Em
6062 // byte bright = (col.r >= 32) + (col.g >= 32) + (col.b >= 32);
6063 // byte sbright = (col.r >= 48) + (col.g >= 48) + (col.b >= 48);
6064 // byte highlightColor = vc(7); //sysgray
6065 // if(bright >= 2)
6066 // {
6067 // if(sbright >= 2)
6068 // highlightColor = vc(0); //sysblack
6069 // else highlightColor = vc(8); //sysdarkgray
6070 // }
6071 // else if(!bright)
6072 // highlightColor = vc(15); //syswhite
6073 // return highlightColor;
6074 }
6075
6076 int32_t jwin_selcolor_proc(int32_t msg, DIALOG *d, int32_t c)
6077 {
6078 int32_t ret = D_O_K;
6079 if(!d->d2) d->d2 = 12;
6080 bool alt = d->d2 > 16;
6081 int32_t numcsets = alt ? 16 : d->d2;
6082 int32_t numcol = numcsets*0x10;
6083 if(msg==MSG_START)
6084 {
6085 d->w = d->h = (16*8) * 1.5;
6086 }
6087 int32_t csz = 12;
6088 d->w = csz * 16;
6089 d->h = csz * numcsets;
6090 switch(msg)
6091 {
6092 case MSG_DRAW:
6093 {
6094 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6095 for(int32_t c = 0; c < numcol; ++c)
6096 {
6097 int32_t x = (c%16)*csz, y = (c/16)*csz;
6098 rectfill(screen, d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1, c);
6099 if(c == d->d1)
6100 {
6101 byte highlightColor = getHighlightColor(c);
6102 rect(screen, d->x+x+0, d->y+y+0, d->x+x+csz-1, d->y+y+csz-1, highlightColor);
6103 rect(screen, d->x+x+1, d->y+y+1, d->x+x+csz-2, d->y+y+csz-2, highlightColor);
6104 }
6105 }
6106
6107 FONT *oldfont = font;
6108
6109 if(d->dp2)
6110 {
6111 font = (FONT*)d->dp2;
6112 }
6113
6114 char buf[32]={0};
6115 for(int32_t col = 0; col < 16; ++col)
6116 {
6117 sprintf(buf, "%X", col);
6118 gui_textout_ln(screen, (uint8_t*)buf, d->x + (csz*col) + (csz/2), d->y-3-text_height(font), scheme[jcBOXFG], scheme[jcBOX], 1);
6119 }
6120 for(int32_t row = 0; row < numcsets; ++row)
6121 {
6122 sprintf(buf, "%s 0x%02X", rowpref(row, alt), row*16);
6123 gui_textout_ln(screen, (uint8_t*)buf, d->x-3, d->y + (csz*row) + (csz-text_height(font))/2, scheme[jcBOXFG], scheme[jcBOX], 2);
6124 }
6125
6126 font = oldfont;
6127 break;
6128 }
6129
6130 case MSG_CLICK:
6131 {
6132 if(mouse_in_rect(d->x, d->y, d->x+d->w-1, d->y+d->h-1))
6133 {
6134 int32_t col = ((gui_mouse_x() - d->x) / csz) + 16*((gui_mouse_y() - d->y) / csz);
6135
6136 // for(int32_t c = 0; c < 0xC0; ++c) //to cset 11
6137 // {
6138 // int32_t x = (c%16)*csz, y = (c/16)*csz;
6139 // if(mouse_in_rect(d->x+x, d->y+y, d->x+x+csz-1, d->y+y+csz-1))
6140 // {
6141 // col = c;
6142 // break;
6143 // }
6144 // }
6145 if(col>-1 && col != d->d1)
6146 {
6147 d->d1 = col;
6148 ret |= D_REDRAWME;
6149 }
6150 ret |= D_WANTFOCUS;
6151 }
6152 break;
6153 }
6154
6155 case MSG_WANTFOCUS:
6156 case MSG_LOSTFOCUS:
6157 case MSG_KEY:
6158 ret = D_WANTFOCUS;
6159 break;
6160
6161 case MSG_CHAR:
6162 {
6163 ret = D_USED_CHAR | D_REDRAWME;
6164 switch(c>>8)
6165 {
6166 case KEY_LEFT:
6167 {
6168 if(d->d1 % 0x10)
6169 --d->d1;
6170 break;
6171 }
6172 case KEY_RIGHT:
6173 {
6174 if(d->d1 % 0x10 != 0x0F)
6175 ++d->d1;
6176 break;
6177 }
6178 case KEY_UP:
6179 {
6180 if(d->d1 / 0x10)
6181 d->d1 -= 0x10;
6182 break;
6183 }
6184 case KEY_DOWN:
6185 {
6186 if(d->d1 / 0x10 != numcsets)
6187 d->d1 += 0x10;
6188 break;
6189 }
6190 case KEY_ENTER:
6191 {
6192 ret = D_CLOSE;
6193 break;
6194 }
6195 default: ret = D_O_K;
6196 }
6197 break;
6198 }
6199 }
6200 return ret;
6201 }
6202
6203 static DIALOG selcolor_dlg[] =
6204 {
6205 { jwin_win_proc, 0, 0, 306, 63+16*8, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Select Color", NULL, NULL },
6206 { jwin_button_proc, 75, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"OK", NULL, NULL },
6207 { jwin_button_proc, 164, 40+16*8, 61, 21, vc(14), vc(1), 0, D_EXIT, 0, 0, (void *)"Cancel", NULL, NULL },
6208 { jwin_selcolor_proc, 156-64, 34, 16*8, 16*8, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6209
6210 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6211 };
6212
6213 int32_t jwin_color_swatch(int32_t msg, DIALOG *d, int32_t c)
6214 {
6215 int32_t ret = D_O_K;
6216
6217 switch(msg)
6218 {
6219 case MSG_START:
6220 {
6221 if(d->d2 < 1) d->d2 = 12;
6222 else if(d->d2 > 17) d->d2 = 17;
6223 break;
6224 }
6225
6226 case MSG_DRAW:
6227 {
6228 if(!d->d1 || (d->flags&D_DISABLED))
6229 {
6230 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1,
6231 (d->flags&D_DISABLED) ? scheme[jcDISABLED_BG] : vc(0));
6232 line(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, vc(15));
6233 line(screen, d->x, d->y+d->h-1, d->x+d->w-1, d->y, vc(15));
6234 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_DEEP);
6235 }
6236 else
6237 {
6238 int32_t c;
6239 switch(d->d1) //special cases
6240 {
6241 case BLACK:
6242 c = vc(0);
6243 break;
6244 case WHITE:
6245 c = vc(15);
6246 break;
6247 default:
6248 c = d->d1;
6249 break;
6250 }
6251 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+d->h-1, c);
6252 jwin_draw_frame(screen, d->x-2, d->y-2, d->w+4, d->h+4, FR_ETCHED);
6253 }
6254 break;
6255 }
6256
6257 case MSG_CLICK:
6258 {
6259 if(d->flags&(D_READONLY|D_DISABLED)) break;
6260 selcolor_dlg[0].dp2 = get_zc_font(font_lfont);
6261 selcolor_dlg[3].bg = scheme[jcBOXFG];
6262 selcolor_dlg[3].fg = scheme[jcBOX];
6263 selcolor_dlg[3].d1 = d->d1;
6264 selcolor_dlg[3].d2 = d->d2;
6265 large_dialog(selcolor_dlg);
6266
6267 while(gui_mouse_b()) rest(1); //wait for mouseup
6268
6269 //!TODO Move this out of jwin, and do better palette management.
6270 //!TODO Allow loading different level palettes, sprite palettes, etc via buttons
6271 PALETTE oldpal;
6272 get_palette(oldpal);
6273 bool alt = d->d2 > 16;
6274 if(!alt)
6275 {
6276 PALETTE foopal;
6277 get_palette(foopal);
6278 foopal[BLACK] = _RGB(0,0,0);
6279 foopal[WHITE] = _RGB(63,63,63);
6280 zc_set_palette(foopal);
6281 }
6282
6283 jwin_center_dialog(selcolor_dlg);
6284 int32_t val = do_zqdialog(selcolor_dlg, 3);
6285 ret = D_REDRAW;
6286
6287 zc_set_palette(oldpal);
6288 if(val == 1 || val == 3)
6289 {
6290 d->d1 = selcolor_dlg[3].d1;
6291 GUI_EVENT(d, geCHANGE_VALUE);
6292 ret |= D_REDRAWME;
6293 }
6294 if(d->flags & D_EXIT)
6295 return D_CLOSE;
6296 break;
6297 }
6298 }
6299 return ret;
6300 }
6301
6302 static DIALOG alert_dialog[] =
6303 {
6304 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6305 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6306 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6307 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6308 { d_ctext2_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6309 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6310 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6311 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6312 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6313 };
6314
6315 #define A_S1 1
6316 #define A_S2 2
6317 #define A_S3 3
6318 #define A_B1 4
6319 #define A_B2 5
6320 #define A_B3 6
6321
6322 /* jwin_alert3:
6323 * Displays a simple alert box, containing three lines of text (s1-s3),
6324 * and with either one, two, or three buttons. The text for these buttons
6325 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6326 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6327 * which button was selected.
6328 */
6329 int32_t jwin_alert3(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6330 {
6331 int32_t maxlen = 0;
6332 int32_t len1, len2, len3;
6333 int32_t avg_w = text_length(font, " ");
6334 int32_t avg_h = text_height(font)+1;
6335 int32_t buttons = 0;
6336 int32_t yofs = (title ? 22 : 0);
6337 int32_t b[3];
6338 int32_t c;
6339
6340 #define SORT_OUT_BUTTON(x) { \
6341 if (b##x) \
6342 { \
6343 alert_dialog[A_B##x].flags &= ~D_HIDDEN; \
6344 alert_dialog[A_B##x].key = c##x; \
6345 alert_dialog[A_B##x].dp = (void *)b##x; \
6346 len##x = gui_strlen(b##x); \
6347 b[buttons++] = A_B##x; \
6348 } \
6349 else \
6350 { \
6351 alert_dialog[A_B##x].flags |= D_HIDDEN; \
6352 len##x = 0; \
6353 } \
6354 }
6355
6356 if(title_font)
6357 {
6358 alert_dialog[0].dp2=title_font;
6359 }
6360
6361 alert_dialog[A_S1].dp = alert_dialog[A_S2].dp = alert_dialog[A_S3].dp =
6362 alert_dialog[A_B1].dp = alert_dialog[A_B2].dp = (void*)"";
6363
6364 if(s1)
6365 {
6366 alert_dialog[A_S1].dp = (void *)s1;
6367 maxlen = text_length(font, s1);
6368 }
6369
6370 if(s2)
6371 {
6372 alert_dialog[A_S2].dp = (void *)s2;
6373 len1 = text_length(font, s2);
6374
6375 if(len1 > maxlen)
6376 maxlen = len1;
6377 }
6378
6379 if(s3)
6380 {
6381 alert_dialog[A_S3].dp = (void *)s3;
6382 len1 = text_length(font, s3);
6383
6384 if(len1 > maxlen)
6385 maxlen = len1;
6386 }
6387
6388 SORT_OUT_BUTTON(1);
6389 SORT_OUT_BUTTON(2);
6390 SORT_OUT_BUTTON(3);
6391
6392 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6393
6394 if(len1*buttons > maxlen)
6395 maxlen = len1*buttons;
6396
6397 maxlen += avg_w*4;
6398 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6399 alert_dialog[0].w = maxlen;
6400 alert_dialog[A_S1].x = alert_dialog[A_S2].x = alert_dialog[A_S3].x =
6401 alert_dialog[0].x + maxlen/2;
6402
6403 alert_dialog[A_B1].w = alert_dialog[A_B2].w = alert_dialog[A_B3].w = len1;
6404
6405 alert_dialog[A_B1].x = alert_dialog[A_B2].x = alert_dialog[A_B3].x =
6406 alert_dialog[0].x + maxlen/2 - len1/2;
6407
6408 if(buttons == 3)
6409 {
6410 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6411 alert_dialog[b[2]].x = alert_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6412 }
6413 else if(buttons == 2)
6414 {
6415 alert_dialog[b[0]].x = alert_dialog[0].x + maxlen/2 - len1 - avg_w;
6416 alert_dialog[b[1]].x = alert_dialog[0].x + maxlen/2 + avg_w;
6417 }
6418
6419 alert_dialog[0].h = avg_h*7 + 13 + yofs;
6420 alert_dialog[A_S1].y = alert_dialog[0].y + avg_h + yofs;
6421 alert_dialog[A_S2].y = alert_dialog[0].y + avg_h*2 + yofs;
6422 alert_dialog[A_S3].y = alert_dialog[0].y + avg_h*3 + yofs;
6423 alert_dialog[A_S1].h = alert_dialog[A_S2].h = alert_dialog[A_S3].h = avg_h;
6424
6425 alert_dialog[A_B1].y = alert_dialog[A_B2].y = alert_dialog[A_B3].y =
6426 alert_dialog[0].y + avg_h*5 + yofs;
6427
6428 alert_dialog[A_B1].h = alert_dialog[A_B2].h = alert_dialog[A_B3].h = avg_h+13;
6429
6430 alert_dialog[0].dp = (void *)title;
6431 alert_dialog[0].flags = (title) ? D_EXIT : 0;
6432
6433 jwin_center_dialog(alert_dialog);
6434 set_dialog_color(alert_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6435
6436 clear_keybuf();
6437
6438 do
6439 {
6440 rest(1);
6441 }
6442 while(gui_mouse_b());
6443
6444 large_dialog(alert_dialog);
6445 alert_dialog[0].d1 = 0;
6446
6447 c = do_zqdialog(alert_dialog, A_B1);
6448
6449 if(c == A_B1)
6450 return 1;
6451 else if(c == A_B2)
6452 return 2;
6453 else
6454 return 3;
6455 }
6456
6457 /* jwin_alert:
6458 * Displays a simple alert box, containing three lines of text (s1-s3),
6459 * and with either one or two buttons. The text for these buttons is passed
6460 * in b1 and b2 (b2 may be null), and the keyboard shortcuts in c1 and c2.
6461 * Returns 1 or 2 depending on which button was selected.
6462 */
6463 int32_t jwin_alert(const char *title, const char *s1, const char *s2, const char *s3, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6464 {
6465 int32_t ret;
6466
6467 ret = jwin_alert3(title, s1, s2, s3, b1, b2, NULL, c1, c2, 0, title_font);
6468
6469 if(ret > 2)
6470 ret = 2;
6471
6472 return ret;
6473 }
6474
6475 int32_t d_autotext_proc(int32_t msg, DIALOG *d, int32_t c)
6476 {
6477 ASSERT(d);
6478 ASSERT(d->dp);
6479 #define AUTOBUF_SIZE 8092
6480 static char auto_buf[AUTOBUF_SIZE] = {0};
6481 static int32_t auto_inds[50] = {0};
6482
6483
6484 FONT *oldfont = font;
6485
6486 if (d->dp2)
6487 font = (FONT*)d->dp2;
6488 switch(msg)
6489 {
6490 case MSG_START:
6491 {
6492 memset(auto_buf, 0, AUTOBUF_SIZE);
6493 memset(auto_inds, 0, 50);
6494 char* str = (char*)d->dp;
6495 int32_t len = strlen(str);
6496 int32_t pos = 0, curstrpos = 0, linecount = 1, lastWS = -1;
6497 BITMAP* dummy = create_bitmap_ex(8,8,8);
6498 for(int32_t q = 0; q < len; ++q)
6499 {
6500 switch(str[q])
6501 {
6502 case ' ': case '\t':
6503 lastWS = pos;
6504 break;
6505 case '\n': //Forced newline
6506 auto_inds[linecount++] = ++pos;
6507 curstrpos = pos;
6508 lastWS = -1;
6509 continue; //skip rest of for loop, go to next char
6510 }
6511 auto_buf[pos++] = str[q];
6512 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //too int32_t, wrap to lower line
6513 {
6514 if(lastWS<0)
6515 {
6516 auto_buf[pos-1] = 0;
6517 auto_inds[linecount++] = pos;
6518 curstrpos = pos;
6519 auto_buf[pos++] = str[q];
6520 }
6521 else
6522 {
6523 auto_buf[lastWS] = 0;
6524 auto_inds[linecount++] = lastWS+1;
6525 curstrpos = lastWS+1;
6526 if(gui_textout_ex(dummy,auto_buf+curstrpos,0,0,0,0,0) >= d->w) //STILL too int32_t?
6527 {
6528 auto_buf[pos-1] = 0;
6529 auto_inds[linecount++] = pos;
6530 curstrpos = pos;
6531 auto_buf[pos++] = str[q];
6532 }
6533 lastWS = -1;
6534 }
6535 }
6536 }
6537 destroy_bitmap(dummy);
6538 d->d2 = linecount;
6539 d->h = ((text_height(font) + d->d1) * linecount) - d->d1;
6540 }
6541 break;
6542
6543 case MSG_DRAW:
6544 {
6545 int32_t fg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
6546 int32_t linecount = d->d2;
6547
6548 int32_t yinc = text_height(font)+d->d1;
6549 int32_t y = d->y;
6550 for(int32_t q = 0; q < linecount; ++q)
6551 {
6552 gui_textout_ex(screen, auto_buf+auto_inds[q], d->x, y, fg, d->bg, true);
6553 y += yinc;
6554 }
6555 }
6556 break;
6557 }
6558 font = oldfont;
6559 return D_O_K;
6560 }
6561
6562 static DIALOG alert2_dialog[] =
6563 {
6564 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
6565 { jwin_win_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6566 { d_autotext_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6567 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6568 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6569 { jwin_button_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6570 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6571 };
6572
6573 #define A2_S1 1
6574 #define A2_B1 2
6575 #define A2_B2 3
6576 #define A2_B3 4
6577
6578 /* jwin_auto_alert3:
6579 * Displays a simple alert box, containing one line of text, auto-split
6580 * across lines using 'lenlim' and 'vspace,
6581 * and with either one, two, or three buttons. The text for these buttons
6582 * is passed in b1, b2, and b3 (NULL for buttons which are not used), and
6583 * the keyboard shortcuts in c1 and c2. Returns 1, 2, or 3 depending on
6584 * which button was selected.
6585 */
6586 int32_t jwin_auto_alert3(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, const char *b3, int32_t c1, int32_t c2, int32_t c3, FONT *title_font)
6587 {
6588 int32_t maxlen = 0;
6589 int32_t len1, len2, len3;
6590 int32_t avg_w = text_length(font, " ");
6591 int32_t avg_h = text_height(font)+1;
6592 int32_t buttons = 0;
6593 int32_t yofs = (title ? 22 : 0);
6594 int32_t b[3];
6595 int32_t c;
6596
6597 #define SORT_OUT_AUTOBUTTON(x) { \
6598 if (b##x) \
6599 { \
6600 alert2_dialog[A2_B##x].flags &= ~D_HIDDEN; \
6601 alert2_dialog[A2_B##x].key = c##x; \
6602 alert2_dialog[A2_B##x].dp = (void *)b##x; \
6603 len##x = gui_strlen(b##x); \
6604 b[buttons++] = A2_B##x; \
6605 } \
6606 else \
6607 { \
6608 alert2_dialog[A2_B##x].flags |= D_HIDDEN; \
6609 len##x = 0; \
6610 } \
6611 }
6612
6613 if(title_font)
6614 {
6615 alert2_dialog[0].dp2=title_font;
6616 }
6617
6618 alert2_dialog[A2_S1].dp = alert2_dialog[A2_B1].dp = alert2_dialog[A2_B2].dp = (void*)"";
6619
6620 if(s1)
6621 {
6622 alert2_dialog[A2_S1].dp = (void *)s1;
6623 maxlen = lenlim;
6624 }
6625
6626 SORT_OUT_AUTOBUTTON(1);
6627 SORT_OUT_AUTOBUTTON(2);
6628 SORT_OUT_AUTOBUTTON(3);
6629
6630 len1 = MAX(len1, MAX(len2, len3)) + avg_w*3;
6631
6632 if(len1*buttons > maxlen)
6633 maxlen = len1*buttons;
6634
6635 maxlen += avg_w*4;
6636 maxlen=zc_max(text_length(title_font?title_font:font,title)+29,maxlen);
6637
6638 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6639 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6640 alert2_dialog[A2_S1].w = lenlim;
6641 alert2_dialog[A2_S1].d1 = vspace;
6642
6643 large_dialog(alert2_dialog);
6644 alert2_dialog[0].d1 = 0;
6645
6646 object_message(&alert2_dialog[A2_S1], MSG_START, 0); //calculate height
6647
6648 alert2_dialog[A2_S1].x = alert2_dialog[0].x + maxlen/2;
6649 alert2_dialog[A2_S1].y = alert2_dialog[0].y + avg_h + yofs;
6650 alert2_dialog[A2_S1].w = lenlim;
6651 alert2_dialog[A2_S1].d1 = vspace;
6652
6653 alert2_dialog[A2_B1].w = alert2_dialog[A2_B2].w = alert2_dialog[A2_B3].w = len1;
6654
6655 alert2_dialog[A2_B1].x = alert2_dialog[A2_B2].x = alert2_dialog[A2_B3].x =
6656 alert2_dialog[0].x + maxlen/2 - len1/2;
6657
6658 if(buttons == 3)
6659 {
6660 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1*3/2 - avg_w;
6661 alert2_dialog[b[2]].x = alert2_dialog[0].x + maxlen/2 + len1/2 + avg_w;
6662 }
6663 else if(buttons == 2)
6664 {
6665 alert2_dialog[b[0]].x = alert2_dialog[0].x + maxlen/2 - len1 - avg_w;
6666 alert2_dialog[b[1]].x = alert2_dialog[0].x + maxlen/2 + avg_w;
6667 }
6668
6669 alert2_dialog[0].w = maxlen;
6670 alert2_dialog[0].h = avg_h*4 + yofs + alert2_dialog[A2_S1].h + 13;
6671 alert2_dialog[A2_B1].y = alert2_dialog[A2_B2].y = alert2_dialog[A2_B3].y =
6672 alert2_dialog[0].y + avg_h*2 + yofs + alert2_dialog[A2_S1].h;
6673
6674 alert2_dialog[A2_B1].h = alert2_dialog[A2_B2].h = alert2_dialog[A2_B3].h = avg_h+13;
6675
6676 alert2_dialog[0].dp = (void *)title;
6677 alert2_dialog[0].flags = (title) ? D_EXIT : 0;
6678
6679 jwin_center_dialog(alert2_dialog);
6680 set_dialog_color(alert2_dialog, scheme[jcTEXTFG], scheme[jcBOX]);
6681
6682 clear_keybuf();
6683
6684 do
6685 {
6686 rest(1);
6687 }
6688 while(gui_mouse_b());
6689
6690 large_dialog(alert2_dialog);
6691 alert2_dialog[0].d1 = 0;
6692
6693 c = do_zqdialog(alert2_dialog, A2_B1);
6694
6695 if(c == A2_B1)
6696 return 1;
6697 else if(c == A2_B2)
6698 return 2;
6699 else
6700 return 3;
6701 }
6702
6703 int32_t jwin_auto_alert(const char *title, const char *s1, int32_t lenlim, int32_t vspace, const char *b1, const char *b2, int32_t c1, int32_t c2, FONT *title_font)
6704 {
6705 int32_t ret;
6706
6707 ret = jwin_auto_alert3(title, s1, lenlim, vspace, b1, b2, NULL, c1, c2, 0, title_font);
6708
6709 if(ret > 2)
6710 ret = 2;
6711
6712 return ret;
6713 }
6714
6715 /*****************************************/
6716 /*********** drop list proc ************/
6717 /*****************************************/
6718 int32_t last_droplist_sel = -1;
6719 static int32_t d_dropcancel_proc(int32_t msg,DIALOG *d,int32_t c)
6720 {
6721 //these are here to bypass compiler warnings about unused arguments
6722 d=d;
6723 c=c;
6724
6725 if(msg==MSG_CLICK || msg==MSG_DCLICK)
6726 return D_CLOSE;
6727
6728 return D_O_K;
6729 }
6730
6731 static DIALOG droplist_dlg[] =
6732 {
6733 /* (dialog proc) (x) (y) (w) (h) (fg) (bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3)*/
6734 { d_dropcancel_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
6735 { d_list_proc, 0, 0, 0, 0, 0, 0, 0, D_EXIT, 0, 0, NULL, NULL, NULL },
6736 { d_keyboard_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_ESC, (void*)close_dlg, NULL, NULL },
6737 { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
6738 };
6739
6740 static int32_t droplist(DIALOG *d)
6741 {
6742 ListData *data = (ListData *)d->dp;
6743 int32_t d1 = d->d1;
6744 int32_t listsize, x, y, w, h, max_w;
6745 auto oz = gui_mouse_z();
6746
6747 data->listFunc(-1, &listsize);
6748 y = d->y + d->h;
6749 h = zc_min(abc_patternmatch ? listsize+1 : listsize,8) * text_height(*data->font) + 8;
6750
6751 if(y+h >= zq_screen_h)
6752 {
6753 y = d->y - h;
6754 }
6755
6756 x = d->x;
6757 w = d->w;
6758 max_w = zc_max(d->x+d->w, zq_screen_w-d->x);
6759
6760 for(int32_t i=0; i<listsize; ++i)
6761 {
6762 w=zc_min(max_w,zc_max(w,text_length(*data->font,data->listFunc(i, NULL))+39));
6763 }
6764
6765 if(x+w >= zq_screen_w)
6766 {
6767 x=zq_screen_w-w;
6768 }
6769
6770 droplist_dlg[1] = *d;
6771 droplist_dlg[1].proc = &jwin_abclist_proc;
6772 droplist_dlg[1].flags = D_EXIT + D_USER;
6773 droplist_dlg[1].x = x;
6774 droplist_dlg[1].y = y;
6775 droplist_dlg[1].w = w;
6776 droplist_dlg[1].h = h;
6777 droplist_dlg[1].d2 = listsize<=8 ? 0 : zc_max(d1-3,0);
6778
6779 // cancel
6780 droplist_dlg[0].x = 0;
6781 droplist_dlg[0].y = 0;
6782 droplist_dlg[0].w = zq_screen_w;
6783 droplist_dlg[0].h = zq_screen_h;
6784
6785 if(do_zq_subdialog(droplist_dlg,1)==1)
6786 {
6787 position_mouse_z(oz);
6788 return droplist_dlg[1].d1;
6789 }
6790
6791 position_mouse_z(oz);
6792 return d1;
6793 }
6794
6795 /* jwin_droplist_proc:
6796 * A drop list...
6797 */
6798 int32_t jwin_droplist_proc(int32_t msg,DIALOG *d,int32_t c)
6799 {
6800 int32_t ret;
6801 int32_t down=0, last_draw=0;
6802 int32_t d1;
6803
6804 switch(msg)
6805 {
6806 case MSG_CLICK:
6807 if(mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h))
6808 goto dropit;
6809
6810 break;
6811
6812 case MSG_KEY:
6813 goto dropit;
6814 break;
6815 }
6816
6817 d1 = d->d1;
6818 ret = jwin_list_proc(msg,d,c);
6819
6820 if(d->d1!=d->d2)
6821 {
6822 d->d1=d->d2;
6823 jwin_droplist_proc(MSG_DRAW, d, 0);
6824 }
6825
6826 if(d1 != d->d1)
6827 {
6828 GUI_EVENT(d, geCHANGE_SELECTION);
6829 if(d->flags&D_EXIT)
6830 ret |= D_CLOSE;
6831 }
6832
6833 if(msg == MSG_DRAW)
6834 {
6835 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6836 }
6837
6838 return ret;
6839
6840 dropit:
6841 last_draw = 0;
6842
6843 while(gui_mouse_b())
6844 {
6845 down = mouse_in_rect(d->x+d->w-18,d->y+2,16,d->h);
6846
6847 if(down!=last_draw)
6848 {
6849 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, down*3);
6850 last_draw = down;
6851 update_hw_screen();
6852 }
6853
6854 clear_keybuf();
6855 rest(1);
6856 }
6857
6858 if(!down)
6859 {
6860 return D_O_K;
6861 }
6862
6863 draw_arrow_button(screen, d->x+d->w-18, d->y+2,16, d->h-4, 0, 0);
6864
6865 d1 = d->d1;
6866 d->d2 = d->d1 = droplist(d);
6867
6868 object_message(d, MSG_DRAW, 0);
6869
6870 while(gui_mouse_b())
6871 {
6872 clear_keybuf();
6873 rest(1);
6874 update_hw_screen();
6875 }
6876
6877 if(d1!=d->d1)
6878 GUI_EVENT(d, geCHANGE_SELECTION);
6879
6880 return ((d1 != d->d1) && (d->flags&D_EXIT)) ? D_CLOSE : D_O_K;
6881 }
6882
6883 /*****************************************/
6884 /************ ABC list proc ************/
6885 /*****************************************/
6886
6887
6888
6889 int32_t jwin_abclist_proc(int32_t msg,DIALOG *d,int32_t c)
6890 {
6891 ListData *data = (ListData *)d->dp;
6892 if(msg == MSG_START) wipe_abc_keypresses();
6893
6894 if(msg == MSG_CHAR && (key_shifts&KB_CTRL_FLAG))
6895 return D_O_K;
6896
6897 if(abc_patternmatch) // Search style pattern match.
6898 {
6899 if(msg==MSG_CHAR && ((c&0xFF) > 31) && ((c&0xFF) < 127)) //(isalpha(c&0xFF) || isdigit(c&0xFF)))
6900 {
6901 int32_t max,dummy,h;
6902
6903 h = ((d->h-3) / text_height(*data->font))-1;
6904 if ( isalpha(c&0xFF) ) c = toupper(c&0xFF);
6905 for ( int32_t q = 0; q < 1023; ++q )
6906 {
6907 if ( !(abc_keypresses[q]) )
6908 {
6909 abc_keypresses[q] = (char)c;
6910 break;
6911 }
6912 }
6913 data->listFunc(-1, &max);
6914
6915 int32_t cur = d->d1;
6916 int32_t charpos = 0; int32_t listpos = 0; int32_t lastmatch = -1;
6917 char tmp[1024] = { 0 };
6918 char lsttmp[1024] = { 0 };
6919 int32_t lastmatches[32768] = {0};
6920 for ( int32_t a = 0; a < 32768; ++a ) lastmatches[a] = -1;
6921 int32_t lmindx = 0;
6922
6923 bool foundmatch = false;
6924 bool numsearch = true;
6925 for ( int32_t q = 0; q < 1023; ++q )
6926 {
6927 if(!abc_keypresses[q]) break;
6928 if(!isdigit(abc_keypresses[q]))
6929 {
6930 if(q == 0 && abc_keypresses[q] == '-')
6931 continue;
6932 numsearch = false;
6933 break;
6934 }
6935 }
6936 if(numsearch) //Indexed search, first
6937 {
6938 int32_t num = atoi(abc_keypresses);
6939 //Find a different indexing type in the strings?
6940 if(!foundmatch)
6941 {
6942 char buf[16];
6943 if(num < 0) sprintf(buf, "(%04d)", num);
6944 else sprintf(buf, "(%03d)", num);
6945 std::string cmp = buf;
6946 for(int32_t listpos = 0; listpos < max; ++listpos)
6947 {
6948 std::string str((data->listFunc(listpos,&dummy)));
6949 size_t trimpos = str.find_last_not_of("-(0123456789)");
6950 if(trimpos != std::string::npos) ++trimpos;
6951 str.erase(0, trimpos);
6952 if(cmp == str)
6953 {
6954 d->d1 = listpos;
6955 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
6956 foundmatch = true;
6957 break;
6958 }
6959 }
6960 }
6961 //Search for match with first number in string?
6962 if(!foundmatch)
6963 {
6964 auto buf = fmt::format("{}", num);
6965 for(int32_t listpos = 0; listpos < max; ++listpos)
6966 {
6967 std::string str((data->listFunc(listpos,&dummy)));
6968 size_t pos1 = -1;
6969 do
6970 {
6971 pos1 = str.find_first_of("-0123456789", pos1+1);
6972 } while(pos1 != string::npos && str[pos1] == '-' && pos1+1 < str.size() && !isdigit(str[pos1+1]));
6973 if(pos1 == string::npos)
6974 continue;
6975 size_t pos2 = str.find_first_not_of("-0123456789", pos1);
6976 if(pos2 == string::npos)
6977 continue;
6978 str = str.substr(pos1,pos2-pos1);
6979 if(buf == str)
6980 {
6981 d->d1 = listpos;
6982 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
6983 foundmatch = true;
6984 break;
6985 }
6986 }
6987 }
6988 }
6989 if(!foundmatch)
6990 {
6991 strcpy(tmp, abc_keypresses);
6992 for ( int32_t listpos = 0; listpos < max; ++listpos )
6993 {
6994 memset(lsttmp, 0, 1024);
6995 strcpy(lsttmp, ((data->listFunc(listpos,&dummy))));
6996
6997 if ( !(strnicmp(lsttmp, tmp, strlen(tmp))))
6998 {
6999 d->d1 = listpos;
7000 d->d2 = zc_max(zc_min(listpos-(h>>1), max-h), 0);
7001 foundmatch = true;
7002 break;
7003 }
7004 }
7005 }
7006 if(foundmatch)
7007 GUI_EVENT(d, geCHANGE_SELECTION);
7008 d->flags |= D_DIRTY;
7009 if ( gui_mouse_b() ) wipe_abc_keypresses();
7010 return foundmatch ? D_USED_CHAR : D_O_K;
7011 }
7012 else if(msg==MSG_CHAR && ( (c&0xFF) == 8) )//backspace
7013 {
7014 for ( int32_t q = 1023; q >= 0; --q )
7015 {
7016 if ( abc_keypresses[q] )
7017 {
7018 d->flags |= D_DIRTY;
7019 abc_keypresses[q] = '\0'; break;
7020 }
7021 }
7022 return D_USED_CHAR;
7023 }
7024 if ( gui_mouse_b() ) { wipe_abc_keypresses(); } //al_trace("keypresses: %s\n", abc_keypresses); }
7025 }
7026 else // Windows Explorer style jumping
7027 {
7028 if(msg==MSG_CHAR && (isalpha(c&0xFF) || isdigit(c&0xFF)))
7029 {
7030 int32_t max,dummy,h,i;
7031
7032 h = (d->h-3) / text_height(*data->font);
7033 c = toupper(c&0xFF);
7034
7035 data->listFunc(-1, &max);
7036
7037 int32_t cur = d->d1;
7038 bool foundmatch = false;
7039 for(i=cur+1; (cur ? (i != cur) : (cur < max)); ++i) //don't infinite loop this.
7040 {
7041 //al_trace("loop running\n");
7042 if(i>=max) i=0;
7043 if(toupper((data->listFunc(i,&dummy))[0]) == c)
7044 {
7045 d->d1 = i;
7046 d->d2 = zc_max(zc_min(i-(h>>1), max-h), 0);
7047 foundmatch = true;
7048 break;
7049 }
7050 }
7051
7052 d->flags |= D_DIRTY;
7053 return foundmatch ? D_USED_CHAR : D_O_K;
7054 }
7055 }
7056 if ( gui_mouse_b() ) { wipe_abc_keypresses(); } //al_trace("keypresses: %s\n", abc_keypresses); }
7057 return ((abc_patternmatch) ? jwin_do_abclist_proc(msg,d,c) : jwin_list_proc(msg,d,c));
7058 }
7059
7060 int32_t jwin_checkfont_proc(int32_t msg, DIALOG *d, int32_t c)
7061 {
7062
7063 FONT *oldfont = font;
7064
7065 if(d->dp2)
7066 {
7067 font = (FONT *)d->dp2;
7068 }
7069
7070 int32_t rval = jwin_check_proc(msg, d, c);
7071 font = oldfont;
7072 return rval;
7073 }
7074
7075 /* jwin_check_proc:
7076 * Who needs C++ after all? This is derived from d_button_proc,
7077 * but overrides the drawing routine to provide a check box.
7078 */
7079 int32_t jwin_check_proc(int32_t msg, DIALOG *d, int32_t c)
7080 {
7081 //these are here to bypass compiler warnings about unused arguments
7082 c=c;
7083 int32_t x;
7084 int32_t bx=0, tl=0;
7085 int32_t tx=d->x;
7086 ASSERT(d);
7087
7088 switch(msg)
7089 {
7090 case MSG_DRAW:
7091 x = d->x;
7092
7093 if(!(d->d1))
7094 {
7095 if(d->dp)
7096 {
7097 if(d->flags & D_DISABLED)
7098 {
7099 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7100 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7101 bx=tl+text_height(font)/2;
7102 }
7103 else
7104 {
7105 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7106 bx=tl+text_height(font)/2;
7107 }
7108 }
7109 }
7110
7111 jwin_draw_frame(screen, x+bx, d->y, d->h, d->h, FR_DEEP);
7112
7113 if(!(d->flags & D_DISABLED))
7114 {
7115 rectfill(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTBG]);
7116 }
7117
7118 if(d->d1)
7119 {
7120 tx=x+bx+d->h-1+(text_height(font)/2);
7121
7122 if(d->dp)
7123 {
7124 if(d->flags & D_DISABLED)
7125 {
7126 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7127 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7128 }
7129 else
7130 {
7131 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7132 }
7133 }
7134 }
7135
7136 if(d->flags & D_SELECTED)
7137 {
7138 line(screen, x+bx+2, d->y+2, x+bx+d->h-3, d->y+d->h-3, scheme[jcTEXTFG]);
7139 line(screen, x+bx+2, d->y+d->h-3, x+bx+d->h-3, d->y+2, scheme[jcTEXTFG]);
7140 }
7141
7142 d->w=int32_t(text_height(font)*1.5);
7143
7144 if(d->dp)
7145 {
7146 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7147 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7148 d->w+=tl+1;
7149 }
7150
7151 return D_O_K;
7152 break;
7153 }
7154
7155 return d_jwinbutton_proc(msg, d, 0);
7156 }
7157
7158 int32_t new_check_proc(int32_t msg, DIALOG *d, int32_t)
7159 {
7160 int32_t bx=0, tl=0;
7161 ASSERT(d);
7162
7163 FONT *oldfont = font;
7164 uint8_t* str = (uint8_t*)d->dp;
7165 bool has_text = str && str[0];
7166 if(d->dp2)
7167 {
7168 font = (FONT *)d->dp2;
7169 }
7170 switch(msg)
7171 {
7172 case MSG_DRAW:
7173 {
7174 const int box_spacing = 4;
7175 int32_t tx = 2, ty = 2, tx2 = 2;
7176 int fh = text_height(font);
7177 auto txt_y = ty+(d->h-fh)/2;
7178 BITMAP* tmp = create_bitmap_ex(8, d->w+4, d->h+4);
7179 clear_bitmap(tmp);
7180 set_clip_rect(tmp, tx, ty, tmp->w-tx, tmp->h-ty);
7181 if(!(d->d1))
7182 {
7183 if(has_text)
7184 {
7185 if(d->flags & D_DISABLED)
7186 {
7187 gui_textout_ln(tmp, str, tx+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7188 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcDISABLED_FG], -1, 0);
7189 bx=tl+box_spacing;
7190 }
7191 else
7192 {
7193 tl=gui_textout_ln(tmp, str, tx, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7194 bx=tl+box_spacing;
7195 }
7196 }
7197 }
7198
7199 jwin_draw_frame(tmp, tx+bx, ty, d->h, d->h, FR_DEEP);
7200
7201 if(!(d->flags & D_DISABLED))
7202 {
7203 rectfill(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTBG]);
7204 }
7205
7206 if(d->d1)
7207 {
7208 tx2=tx+bx+d->h-1+box_spacing;
7209
7210 if(has_text)
7211 {
7212 if(d->flags & D_DISABLED)
7213 {
7214 gui_textout_ln(tmp, str, tx2+1, txt_y+1, scheme[jcLIGHT], scheme[jcBOX], 0);
7215 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcDISABLED_FG], -1, 0);
7216 }
7217 else
7218 {
7219 tl=gui_textout_ln(tmp, str, tx2, txt_y, scheme[jcBOXFG], scheme[jcBOX], 0);
7220 }
7221 }
7222 }
7223
7224 if(d->flags & D_SELECTED)
7225 {
7226 line(tmp, tx+bx+2, ty+2, tx+bx+d->h-3, ty+d->h-3, scheme[jcTEXTFG]);
7227 line(tmp, tx+bx+2, ty+d->h-3, tx+bx+d->h-3, ty+2, scheme[jcTEXTFG]);
7228 }
7229
7230 set_clip_rect(tmp, 0, 0, tmp->w, tmp->h);
7231 if(has_text)
7232 {
7233 dotted_rect(tmp, tx2-1, txt_y-1, tx2+tl, txt_y+fh, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7234 }
7235
7236 masked_blit(tmp, screen, 0, 0, d->x-tx, d->y-ty, d->w+tx+tx, d->h+ty+ty);
7237 break;
7238 }
7239 }
7240
7241 int32_t rval = D_O_K;
7242 if(msg != MSG_DRAW)
7243 rval = d_jwinbutton_proc(msg, d, 0);
7244 font = oldfont;
7245 return rval;
7246 }
7247
7248 int32_t jwin_radiofont_proc(int32_t msg, DIALOG *d, int32_t c)
7249 {
7250 FONT *oldfont = font;
7251
7252 if(d->dp2)
7253 {
7254 font = (FONT *)d->dp2;
7255 }
7256
7257 int32_t rval = jwin_radio_proc(msg, d, c);
7258 font = oldfont;
7259 return rval;
7260 }
7261
7262 /* jwin_radio_proc:
7263 * GUI procedure for radio buttons.
7264 * Parameters: d1-button group number; d2-button style (0=circle,1=square);
7265 * dp-text to appear as label to the right of the button.
7266 */
7267 int32_t jwin_radio_proc(int32_t msg, DIALOG *d, int32_t c)
7268 {
7269 int32_t x, center, r, ret, tl=0, tx;
7270 ASSERT(d);
7271
7272 switch(msg)
7273 {
7274 case MSG_DRAW:
7275 // tx=d->x+d->h-1+text_height(font);
7276 tx=d->x+int32_t(text_height(font)*1.5);
7277
7278 if(d->dp)
7279 {
7280 if(d->flags & D_DISABLED)
7281 {
7282 gui_textout_ln(screen, (uint8_t *)d->dp, tx+1, d->y+1+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcLIGHT], scheme[jcBOX], 0);
7283 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcDISABLED_FG], -1, 0);
7284 }
7285 else
7286 {
7287 tl=gui_textout_ln(screen, (uint8_t *)d->dp, tx, d->y+(d->h-(text_height(font)-gui_font_baseline))/2, scheme[jcBOXFG], scheme[jcBOX], 0);
7288 }
7289 }
7290
7291 x = d->x;
7292 r = d->h/2;
7293
7294 center = x+r;
7295 rectfill(screen, x, d->y, x+d->h-1, d->y+d->h-1, scheme[jcBOX]);
7296
7297 switch(d->d2)
7298 {
7299 case 1:
7300 jwin_draw_frame(screen, x, d->y, d->h, d->h, FR_DEEP);
7301
7302 if(!(d->flags & D_DISABLED))
7303 {
7304 rectfill(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcLIGHT]);
7305 }
7306
7307 if(d->flags & D_SELECTED)
7308 {
7309 rectfill(screen, x+r/2, d->y+r/2, x+d->h-1-r/2, d->y+d->h-1-r/2, scheme[jcDARK]);
7310 //line(screen, x+2, d->y+2, x+d->h-3, d->y+d->h-3, scheme[jcDARK]);
7311 //line(screen, x+2, d->y+d->h-3, x+d->h-3, d->y+2, scheme[jcDARK]);
7312 }
7313
7314 break;
7315
7316 default:
7317 circlefill(screen, center, d->y+r, r, scheme[jcTEXTBG]);
7318 arc(screen, center, d->y+r, itofix(32), itofix(160), r, vc(0));
7319 circlefill(screen, center, d->y+r, r-1, scheme[jcTEXTBG]);
7320 arc(screen, center, d->y+r, itofix(32), itofix(160), r-1, vc(0));
7321 circlefill(screen, center, d->y+r, r-2, (d->flags & D_DISABLED)?scheme[jcDISABLED_BG]:scheme[jcTEXTBG]);
7322
7323 if(d->flags & D_SELECTED)
7324 {
7325 circlefill(screen, center, d->y+r, r-3, scheme[jcTEXTFG]);
7326 }
7327
7328 break;
7329 }
7330
7331 if(d->dp)
7332 {
7333 // dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+d->h-1, (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7334 dotted_rect(screen, tx-1, d->y-1, tx+tl, d->y+(text_height(font)), (d->flags & D_GOTFOCUS)?scheme[jcDARK]:scheme[jcBOX], scheme[jcBOX]);
7335 d->w=tl+int32_t(text_height(font)*1.5)+1;
7336 }
7337
7338 return D_O_K;
7339
7340 case MSG_KEY:
7341 case MSG_CLICK:
7342 if(d->flags & D_SELECTED)
7343 {
7344 return D_O_K;
7345 }
7346
7347 break;
7348
7349 case MSG_RADIO:
7350 if((c == d->d1) && (d->flags & D_SELECTED))
7351 {
7352 d->flags &= ~D_SELECTED;
7353 object_message(d, MSG_DRAW, 0);
7354 }
7355
7356 break;
7357 }
7358
7359 ret = d_jwinbutton_proc(msg, d, 0);
7360
7361 if(((msg==MSG_KEY) || (msg==MSG_CLICK)) && (d->flags & D_SELECTED) && (!(d->flags & D_EXIT)))
7362 {
7363 d->flags &= ~D_SELECTED;
7364 broadcast_dialog_message(MSG_RADIO, d->d1);
7365 d->flags |= D_SELECTED;
7366 GUI_EVENT(d, geRADIO);
7367 }
7368
7369 return ret;
7370 }
7371
7372
7373 /* 1.5k lookup table for color matching */
7374 uint32_t col_diff[3*128];
7375
7376 /* bestfit_init:
7377 * Color matching is done with weighted squares, which are much faster
7378 * if we pregenerate a little lookup table...
7379 */
7380 68 void bestfit_init(void)
7381 {
7382 int32_t i;
7383
7384 68 col_diff[0] = col_diff[128] = col_diff[256] = 0;
7385
7386
2/2
✓ Branch 0 taken 4284 times.
✓ Branch 1 taken 68 times.
4352 for(i=1; i<64; i++)
7387 {
7388 4284 int32_t k = i * i;
7389 4284 col_diff[0 +i] = col_diff[0 +128-i] = k * (59 * 59);
7390 4284 col_diff[128+i] = col_diff[128+128-i] = k * (30 * 30);
7391 4284 col_diff[256+i] = col_diff[256+128-i] = k * (11 * 11);
7392 4284 }
7393 68 }
7394
7395
7396
7397 /* bestfit_color:
7398 * Searches a palette for the color closest to the requested R, G, B value.
7399 */
7400 int32_t bestfit_color_range(AL_CONST PALETTE pal, int32_t r, int32_t g, int32_t b, uint8_t start, uint8_t end)
7401 {
7402 int32_t i, coldiff, lowest, bestfit;
7403
7404 if(col_diff[1] == 0)
7405 bestfit_init();
7406
7407 bestfit = start;
7408 lowest = INT_MAX;
7409
7410 i = start;
7411
7412 while(i<PAL_SIZE&&i<=end)
7413 {
7414 AL_CONST RGB *rgb = &pal[i];
7415 coldiff = (col_diff + 0) [(rgb->g - g) & 0x7F ];
7416
7417 if(coldiff < lowest)
7418 {
7419 coldiff += (col_diff + 128) [(rgb->r - r) & 0x7F ];
7420
7421 if(coldiff < lowest)
7422 {
7423 coldiff += (col_diff + 256) [(rgb->b - b) & 0x7F ];
7424
7425 if(coldiff < lowest)
7426 {
7427 bestfit = rgb - pal; /* faster than `bestfit = i;' */
7428
7429 if(coldiff == 0)
7430 {
7431 return bestfit;
7432 }
7433
7434 lowest = coldiff;
7435 }
7436 }
7437 }
7438
7439 i++;
7440 }
7441
7442 return bestfit;
7443 }
7444
7445
7446 /* makecol8:
7447 * Converts R, G, and B values (ranging 0-255) to an 8 bit paletted color.
7448 * If the global rgb_map table is initialised, it uses that, otherwise
7449 * it searches through the current palette to find the best match.
7450 */
7451 int32_t makecol8_map(int32_t r, int32_t g, int32_t b, RGB_MAP *table)
7452 {
7453 return table->data[r>>3][g>>3][b>>3];
7454 }
7455
7456
7457 /* create_rgb_table:
7458 * Fills an RGB_MAP lookup table with conversion data for the specified
7459 * palette. This is the faster version by Jan Hubicka.
7460 *
7461 * Uses alg. similar to floodfill - it adds one seed per every color in
7462 * palette to its best position. Then areas around seed are filled by
7463 * same color because it is best approximation for them, and then areas
7464 * about them etc...
7465 *
7466 * It does just about 80000 tests for distances and this is about 100
7467 * times better than normal 256*32000 tests so the calculation time
7468 * is now less than one second at all computers I tested.
7469 */
7470 8160 void create_rgb_table_range(RGB_MAP *table, AL_CONST PALETTE pal, uint8_t start, uint8_t end, void (*callback)(int32_t pos))
7471 {
7472 #define UNUSED 65535
7473 #define LAST 65532
7474
7475 /* macro add adds to single linked list */
7476 #define add(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7477 (first != LAST ? (next[last] = (i)) : (first = (i))), \
7478 (last = (i))) : 0)
7479
7480 /* same but w/o checking for first element */
7481 #define add1(i) (next[(i)] == UNUSED ? (next[(i)] = LAST, \
7482 next[last] = (i), \
7483 (last = (i))) : 0)
7484
7485 /* calculates distance between two colors */
7486 #define dist(a1, a2, a3, b1, b2, b3) \
7487 (col_diff[ ((a2) - (b2)) & 0x7F] + \
7488 (col_diff + 128)[((a1) - (b1)) & 0x7F] + \
7489 (col_diff + 256)[((a3) - (b3)) & 0x7F])
7490
7491 /* converts r,g,b to position in array and back */
7492 #define pos(r, g, b) \
7493 (((r) / 2) * 32 * 32 + ((g) / 2) * 32 + ((b) / 2))
7494
7495 #define depos(pal, r, g, b) \
7496 ((b) = ((pal) & 31) * 2, \
7497 (g) = (((pal) >> 5) & 31) * 2, \
7498 (r) = (((pal) >> 10) & 31) * 2)
7499
7500 /* is current color better than pal1? */
7501 #define better(r1, g1, b1, pal1) \
7502 (((int32_t)dist((r1), (g1), (b1), \
7503 (pal1).r, (pal1).g, (pal1).b)) > (int32_t)dist2)
7504
7505 /* checking of position */
7506 #define dopos(rp, gp, bp, ts) \
7507 if ((rp > -1 || r > 0) && (rp < 1 || r < 61) && \
7508 (gp > -1 || g > 0) && (gp < 1 || g < 61) && \
7509 (bp > -1 || b > 0) && (bp < 1 || b < 61)) { \
7510 i = first + rp * 32 * 32 + gp * 32 + bp; \
7511 if (!data[i]) { \
7512 data[i] = val; \
7513 add1(i); \
7514 } \
7515 else if ((ts) && (data[i] != val)) { \
7516 dist2 = (rp ? (col_diff+128)[(r+2*rp-pal[val].r) & 0x7F] : r2) + \
7517 (gp ? (col_diff )[(g+2*gp-pal[val].g) & 0x7F] : g2) + \
7518 (bp ? (col_diff+256)[(b+2*bp-pal[val].b) & 0x7F] : b2); \
7519 if (better((r+2*rp), (g+2*gp), (b+2*bp), pal[data[i]])) { \
7520 data[i] = val; \
7521 add1(i); \
7522 } \
7523 } \
7524 }
7525
7526 int32_t i, curr, r, g, b, val, dist2;
7527 uint32_t r2, g2, b2;
7528 uint16_t next[32*32*32];
7529 uint8_t *data;
7530 8160 int32_t first = LAST;
7531 8160 int32_t last = LAST;
7532 8160 int32_t count = 0;
7533 8160 int32_t cbcount = 0;
7534
7535 #define AVERAGE_COUNT 18000
7536
7537
2/2
✓ Branch 0 taken 8100 times.
✓ Branch 1 taken 60 times.
8160 if(col_diff[1] == 0)
7538 60 bestfit_init();
7539
7540 8160 memset(next, 255, sizeof(next));
7541 8160 memset(table->data, 0, sizeof(char)*32*32*32);
7542
7543 8160 data = (uint8_t *)table->data;
7544
7545 /* add starting seeds for floodfill */
7546
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 269280 times.
✓ Branch 2 taken 261120 times.
✓ Branch 3 taken 8160 times.
269280 for(i=start; i<PAL_SIZE&&i<=end; i++)
7547 {
7548 261120 curr = pos(pal[i].r, pal[i].g, pal[i].b);
7549
7550
2/2
✓ Branch 0 taken 96390 times.
✓ Branch 1 taken 164730 times.
261120 if(next[curr] == UNUSED)
7551 {
7552 164730 data[curr] = i;
7553
3/4
✓ Branch 0 taken 164730 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 156570 times.
✓ Branch 3 taken 8160 times.
164730 add(curr);
7554 164730 }
7555 261120 }
7556
7557 /* main floodfill: two versions of loop for faster growing in blue axis */
7558
2/2
✓ Branch 0 taken 8160 times.
✓ Branch 1 taken 155277915 times.
155286075 while(first < LAST)
7559 {
7560 155277915 depos(first, r, g, b);
7561
7562 /* calculate distance of current color */
7563 155277915 val = data[first];
7564 155277915 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7565 155277915 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7566 155277915 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7567
7568 /* try to grow to all directions */
7569 #ifdef _MSC_VER
7570 #pragma warning(disable:4127)
7571 #endif
7572
11/12
✓ Branch 0 taken 4190925 times.
✓ Branch 1 taken 151086990 times.
✓ Branch 2 taken 137954745 times.
✓ Branch 3 taken 13132245 times.
✓ Branch 4 taken 13132245 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 127112400 times.
✓ Branch 7 taken 10842345 times.
✓ Branch 8 taken 3005940 times.
✓ Branch 9 taken 7836405 times.
✓ Branch 10 taken 23970 times.
✓ Branch 11 taken 7812435 times.
293232660 dopos(0, 0, 1, 1);
7573
11/12
✓ Branch 0 taken 7108635 times.
✓ Branch 1 taken 148169280 times.
✓ Branch 2 taken 148159335 times.
✓ Branch 3 taken 9945 times.
✓ Branch 4 taken 9945 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 146508720 times.
✓ Branch 7 taken 1650615 times.
✓ Branch 8 taken 677025 times.
✓ Branch 9 taken 973590 times.
✓ Branch 10 taken 954210 times.
✓ Branch 11 taken 19380 times.
303437250 dopos(0, 0,-1, 1);
7574
11/12
✓ Branch 0 taken 4244220 times.
✓ Branch 1 taken 151033695 times.
✓ Branch 2 taken 150128445 times.
✓ Branch 3 taken 905250 times.
✓ Branch 4 taken 905250 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 118205250 times.
✓ Branch 7 taken 31923195 times.
✓ Branch 8 taken 31876020 times.
✓ Branch 9 taken 47175 times.
✓ Branch 10 taken 7395 times.
✓ Branch 11 taken 39780 times.
305406360 dopos(1, 0, 0, 1);
7575
11/12
✓ Branch 0 taken 6459405 times.
✓ Branch 1 taken 148818510 times.
✓ Branch 2 taken 148807545 times.
✓ Branch 3 taken 10965 times.
✓ Branch 4 taken 10965 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 113494125 times.
✓ Branch 7 taken 35313420 times.
✓ Branch 8 taken 28788225 times.
✓ Branch 9 taken 6525195 times.
✓ Branch 10 taken 6111075 times.
✓ Branch 11 taken 414120 times.
304085460 dopos(-1, 0, 0, 1);
7576
11/12
✓ Branch 0 taken 5374380 times.
✓ Branch 1 taken 149903535 times.
✓ Branch 2 taken 128596755 times.
✓ Branch 3 taken 21306780 times.
✓ Branch 4 taken 21306780 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 108714150 times.
✓ Branch 7 taken 19882605 times.
✓ Branch 8 taken 3464175 times.
✓ Branch 9 taken 16418430 times.
✓ Branch 10 taken 14399340 times.
✓ Branch 11 taken 2019090 times.
283874670 dopos(0, 1, 0, 1);
7577
11/12
✓ Branch 0 taken 4112895 times.
✓ Branch 1 taken 151165020 times.
✓ Branch 2 taken 150969945 times.
✓ Branch 3 taken 195075 times.
✓ Branch 4 taken 195075 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139072155 times.
✓ Branch 7 taken 11897790 times.
✓ Branch 8 taken 11789670 times.
✓ Branch 9 taken 108120 times.
✓ Branch 10 taken 75480 times.
✓ Branch 11 taken 32640 times.
306247860 dopos(0,-1, 0, 1);
7578 #ifdef _MSC_VER
7579 #pragma warning(default:4127)
7580 #endif
7581
7582 /* faster growing of blue direction */
7583
4/4
✓ Branch 0 taken 148169280 times.
✓ Branch 1 taken 7108635 times.
✓ Branch 2 taken 677025 times.
✓ Branch 3 taken 147492255 times.
155277915 if((b > 0) && (data[first-1] == val))
7584 {
7585 147492255 b -= 2;
7586 147492255 first--;
7587 147492255 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7588
7589 #ifdef _MSC_VER
7590 #pragma warning(disable:4127)
7591 #endif
7592
5/6
✓ Branch 0 taken 6071040 times.
✓ Branch 1 taken 141421215 times.
✓ Branch 2 taken 141419940 times.
✓ Branch 3 taken 1275 times.
✓ Branch 4 taken 1275 times.
✗ Branch 5 not taken.
288912195 dopos(-1, 0, 0, 0);
7593
5/6
✓ Branch 0 taken 4115190 times.
✓ Branch 1 taken 143377065 times.
✓ Branch 2 taken 143296230 times.
✓ Branch 3 taken 80835 times.
✓ Branch 4 taken 80835 times.
✗ Branch 5 not taken.
290788485 dopos(1, 0, 0, 0);
7594
5/6
✓ Branch 0 taken 3956580 times.
✓ Branch 1 taken 143535675 times.
✓ Branch 2 taken 143497170 times.
✓ Branch 3 taken 38505 times.
✓ Branch 4 taken 38505 times.
✗ Branch 5 not taken.
290989425 dopos(0,-1, 0, 0);
7595
5/6
✓ Branch 0 taken 5103570 times.
✓ Branch 1 taken 142388685 times.
✓ Branch 2 taken 141890925 times.
✓ Branch 3 taken 497760 times.
✓ Branch 4 taken 497760 times.
✗ Branch 5 not taken.
289383180 dopos(0, 1, 0, 0);
7596 #ifdef _MSC_VER
7597 #pragma warning(default:4127)
7598 #endif
7599
7600 147492255 first++;
7601 147492255 }
7602
7603 /* get next from list */
7604 155277915 i = first;
7605 155277915 first = next[first];
7606 155277915 next[i] = UNUSED;
7607
7608 /* second version of loop */
7609
2/2
✓ Branch 0 taken 6375 times.
✓ Branch 1 taken 155271540 times.
155277915 if(first != LAST)
7610 {
7611 155271540 depos(first, r, g, b);
7612
7613 155271540 val = data[first];
7614 155271540 r2 = (col_diff+128)[((pal[val].r)-(r)) & 0x7F];
7615 155271540 g2 = (col_diff)[((pal[val].g)-(g)) & 0x7F];
7616 155271540 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7F];
7617
7618 #ifdef _MSC_VER
7619 #pragma warning(disable:4127)
7620 #endif
7621
11/12
✓ Branch 0 taken 4189905 times.
✓ Branch 1 taken 151081635 times.
✓ Branch 2 taken 135099255 times.
✓ Branch 3 taken 15982380 times.
✓ Branch 4 taken 15982380 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 125926650 times.
✓ Branch 7 taken 9172605 times.
✓ Branch 8 taken 3044700 times.
✓ Branch 9 taken 6127905 times.
✓ Branch 10 taken 24480 times.
✓ Branch 11 taken 6103425 times.
290370795 dopos(0, 0, 1, 1);
7622
11/12
✓ Branch 0 taken 7164225 times.
✓ Branch 1 taken 148107315 times.
✓ Branch 2 taken 148105785 times.
✓ Branch 3 taken 1530 times.
✓ Branch 4 taken 1530 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 146507445 times.
✓ Branch 7 taken 1598340 times.
✓ Branch 8 taken 640305 times.
✓ Branch 9 taken 958035 times.
✓ Branch 10 taken 937635 times.
✓ Branch 11 taken 20400 times.
303377325 dopos(0, 0,-1, 1);
7623
11/12
✓ Branch 0 taken 4111620 times.
✓ Branch 1 taken 151159920 times.
✓ Branch 2 taken 149930055 times.
✓ Branch 3 taken 1229865 times.
✓ Branch 4 taken 1229865 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117763590 times.
✓ Branch 7 taken 32166465 times.
✓ Branch 8 taken 32131530 times.
✓ Branch 9 taken 34935 times.
✓ Branch 10 taken 6375 times.
✓ Branch 11 taken 28560 times.
305201595 dopos(1, 0, 0, 1);
7624
11/12
✓ Branch 0 taken 6240870 times.
✓ Branch 1 taken 149030670 times.
✓ Branch 2 taken 149016390 times.
✓ Branch 3 taken 14280 times.
✓ Branch 4 taken 14280 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 113588475 times.
✓ Branch 7 taken 35427915 times.
✓ Branch 8 taken 28836165 times.
✓ Branch 9 taken 6591750 times.
✓ Branch 10 taken 6232455 times.
✓ Branch 11 taken 359295 times.
304287930 dopos(-1, 0, 0, 1);
7625
11/12
✓ Branch 0 taken 5488620 times.
✓ Branch 1 taken 149782920 times.
✓ Branch 2 taken 104060910 times.
✓ Branch 3 taken 45722010 times.
✓ Branch 4 taken 45722010 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 84990225 times.
✓ Branch 7 taken 19070685 times.
✓ Branch 8 taken 3372120 times.
✓ Branch 9 taken 15698565 times.
✓ Branch 10 taken 14296320 times.
✓ Branch 11 taken 1402245 times.
259332450 dopos(0, 1, 0, 1);
7626
11/12
✓ Branch 0 taken 4277115 times.
✓ Branch 1 taken 150994425 times.
✓ Branch 2 taken 150742485 times.
✓ Branch 3 taken 251940 times.
✓ Branch 4 taken 251940 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 139028550 times.
✓ Branch 7 taken 11713935 times.
✓ Branch 8 taken 11591025 times.
✓ Branch 9 taken 122910 times.
✓ Branch 10 taken 93840 times.
✓ Branch 11 taken 29070 times.
306014025 dopos(0,-1, 0, 1);
7627 #ifdef _MSC_VER
7628 #pragma warning(default:4127)
7629 #endif
7630
7631
4/4
✓ Branch 0 taken 151081635 times.
✓ Branch 1 taken 4189905 times.
✓ Branch 2 taken 3044700 times.
✓ Branch 3 taken 148036935 times.
155271540 if((b < 61) && (data[first + 1] == val))
7632 {
7633 148036935 b += 2;
7634 148036935 first++;
7635 148036935 b2 = (col_diff+256)[((pal[val].b)-(b)) & 0x7f];
7636
7637 #ifdef _MSC_VER
7638 #pragma warning(disable:4127)
7639 #endif
7640
5/6
✓ Branch 0 taken 5916255 times.
✓ Branch 1 taken 142120680 times.
✓ Branch 2 taken 133678905 times.
✓ Branch 3 taken 8441775 times.
✓ Branch 4 taken 8441775 times.
✗ Branch 5 not taken.
281715840 dopos(-1, 0, 0, 0);
7641
5/6
✓ Branch 0 taken 3993300 times.
✓ Branch 1 taken 144043635 times.
✓ Branch 2 taken 98826525 times.
✓ Branch 3 taken 45217110 times.
✓ Branch 4 taken 45217110 times.
✗ Branch 5 not taken.
246863460 dopos(1, 0, 0, 0);
7642
5/6
✓ Branch 0 taken 4136355 times.
✓ Branch 1 taken 143900580 times.
✓ Branch 2 taken 140247450 times.
✓ Branch 3 taken 3653130 times.
✓ Branch 4 taken 3653130 times.
✗ Branch 5 not taken.
288284385 dopos(0,-1, 0, 0);
7643
5/6
✓ Branch 0 taken 5200980 times.
✓ Branch 1 taken 142835955 times.
✓ Branch 2 taken 32306460 times.
✓ Branch 3 taken 110529495 times.
✓ Branch 4 taken 110529495 times.
✗ Branch 5 not taken.
180343395 dopos(0, 1, 0, 0);
7644 #ifdef _MSC_VER
7645 #pragma warning(default:4127)
7646 #endif
7647
7648 148036935 first--;
7649 148036935 }
7650
7651 155271540 i = first;
7652 155271540 first = next[first];
7653 155271540 next[i] = UNUSED;
7654 155271540 }
7655
7656 155277915 count++;
7657
7658
2/2
✓ Branch 0 taken 153182580 times.
✓ Branch 1 taken 2095335 times.
155277915 if(count == (cbcount+1)*AVERAGE_COUNT/256)
7659 {
7660
2/2
✓ Branch 0 taken 6375 times.
✓ Branch 1 taken 2088960 times.
2095335 if(cbcount < 256)
7661 {
7662
1/2
✓ Branch 0 taken 2088960 times.
✗ Branch 1 not taken.
2088960 if(callback)
7663 callback(cbcount);
7664
7665 2088960 cbcount++;
7666 2088960 }
7667 2095335 }
7668 }
7669
7670
1/2
✓ Branch 0 taken 8160 times.
✗ Branch 1 not taken.
8160 if(callback)
7671 while(cbcount < 256)
7672 callback(cbcount++);
7673 8160 }
7674
7675 int32_t short_bmp_avg(BITMAP *bmp, int32_t i)
7676 {
7677 int32_t j=((int16_t *)bmp->line[0])[i];
7678 int32_t r=getr15(j);
7679 int32_t g=getg15(j);
7680 int32_t b=getb15(j);
7681 int32_t k=1;
7682
7683 if(i>0)
7684 {
7685 j=((int16_t *)bmp->line[0])[i-1];
7686 r+=getr15(j);
7687 g+=getg15(j);
7688 b+=getb15(j);
7689 ++k;
7690 }
7691
7692 if(i<(bmp->w-2))
7693 {
7694 j=((int16_t *)bmp->line[0])[i+1];
7695 r+=getr15(j);
7696 g+=getg15(j);
7697 b+=getb15(j);
7698 ++k;
7699 }
7700
7701 r/=k;
7702 g/=k;
7703 b/=k;
7704 return makecol15(r, g, b);
7705 }
7706
7707 // A consistent RENG (random enough number generator) for dither_rect()
7708 static uint16_t lfsr;
7709
7710 void lfsrInit()
7711 {
7712 lfsr=1;
7713 }
7714
7715 uint16_t lfsrNext()
7716 {
7717 auto bits=(lfsr^(lfsr>>2)^(lfsr>>3)^(lfsr>>5))&1;
7718 lfsr=(lfsr>>1)|(bits<<15);
7719 return lfsr;
7720 }
7721
7722 void dither_rect(BITMAP *bmp, PALETTE *pal, int32_t x1, int32_t y1, int32_t x2, int32_t y2,
7723 int32_t src_color1, int32_t src_color2, uint8_t dest_color1,
7724 uint8_t dest_color2)
7725 {
7726 BITMAP *src_bmp=create_bitmap_ex(15, abs(x2-x1)+1, 1);
7727 BITMAP *dest_bmp=create_bitmap_ex(8, abs(x2-x1)+1, abs(y2-y1)+1);
7728 int32_t r, g, b, direction=1;
7729 int32_t c;
7730 int32_t r1, r2, g1, g2, b1, b2;
7731 // int32_t diff[2][x2-x1+3][3];
7732 int32_t (*diff[2])[3];
7733 diff[0] = new int32_t[x2-x1+3][3];
7734 diff[1] = new int32_t[x2-x1+3][3];
7735 int32_t cdiff[3];
7736 RGB_MAP table;
7737 int32_t temp;
7738 int32_t red_rand_strength=0, green_rand_strength=0, blue_rand_strength=0;
7739
7740 lfsrInit();
7741 clear_bitmap(dest_bmp);
7742
7743 if(x1>x2)
7744 {
7745 temp=x1;
7746 x1=x2;
7747 x2=temp;
7748 }
7749
7750 if(y1>y2)
7751 {
7752 temp=y1;
7753 y1=y2;
7754 y2=temp;
7755 }
7756
7757 if(src_color1>src_color2)
7758 {
7759 temp=src_color1;
7760 src_color1=src_color2;
7761 src_color2=temp;
7762 }
7763
7764 if(dest_color1>dest_color2)
7765 {
7766 temp=dest_color1;
7767 dest_color1=dest_color2;
7768 dest_color2=temp;
7769 }
7770
7771 create_rgb_table_range(&table, *pal, dest_color1, dest_color2, NULL);
7772 r1=getr15(src_color1);
7773 r2=getr15(src_color2);
7774 g1=getg15(src_color1);
7775 g2=getg15(src_color2);
7776 b1=getb15(src_color1);
7777 b2=getb15(src_color2);
7778 red_rand_strength=getr8(dest_color1+1)-getr8(dest_color1);
7779 green_rand_strength=getg8(dest_color1+1)-getg8(dest_color1);
7780 blue_rand_strength=getb8(dest_color1+1)-getb8(dest_color1);
7781 memset(cdiff,0,3*sizeof(float));
7782 memset(diff[0],0,(x2-x1+3)*3*sizeof(int32_t));
7783 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7784 int32_t mc, mr, mg, mb;
7785
7786 for(int32_t i=0; i<src_bmp->w; i++)
7787 {
7788 r = mix_value(r1, r2, i, src_bmp->w-1);
7789 g = mix_value(g1, g2, i, src_bmp->w-1);
7790 b = mix_value(b1, b2, i, src_bmp->w-1);
7791 c = makecol15(r,g,b);
7792 ((int16_t *)src_bmp->line[0])[i] = c;
7793 }
7794
7795 uint8_t tempcolor, origcolor;
7796
7797 for(int32_t j=0; j<=y2-y1; ++j)
7798 {
7799 if(direction==1)
7800 {
7801 for(int32_t i=0; i<=x2-x1; ++i)
7802 {
7803 mc=((int16_t *)src_bmp->line[0])[i];
7804 mr=bound(getr15(mc)+lfsrNext()%(red_rand_strength*2+1)-(red_rand_strength*1),0,255);
7805 mg=bound(getg15(mc)+lfsrNext()%(green_rand_strength*2+1)-(green_rand_strength*1),0,255);
7806 mb=bound(getb15(mc)+lfsrNext()%(blue_rand_strength*2+1)-(blue_rand_strength*1),0,255);
7807 cdiff[0]=bound(mr+
7808 diff[0][i][0]+
7809 diff[0][i+1][0]+
7810 diff[0][i+2][0]+
7811 cdiff[0],0,255);
7812 cdiff[1]=bound(mg+
7813 diff[0][i][1]+
7814 diff[0][i+1][1]+
7815 diff[0][i+2][1]+
7816 cdiff[1],0,255);
7817 cdiff[2]=bound(mb+
7818 diff[0][i][2]+
7819 diff[0][i+1][2]+
7820 diff[0][i+2][2]+
7821 cdiff[2],0,255);
7822 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7823 origcolor=makecol8_map(mr,mg,mb,&table);
7824 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7825 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7826 dest_bmp->line[j][i]=tempcolor;
7827 r=getr8(tempcolor);
7828 g=getg8(tempcolor);
7829 b=getb8(tempcolor);
7830 diff[1][i][0]=(cdiff[0]-r)*3/16;
7831 diff[1][i][1]=(cdiff[1]-g)*3/16;
7832 diff[1][i][2]=(cdiff[2]-b)*3/16;
7833 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7834 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7835 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7836 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7837 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7838 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7839 cdiff[0]=(cdiff[0]-r)*7/16;
7840 cdiff[1]=(cdiff[1]-g)*7/16;
7841 cdiff[2]=(cdiff[2]-b)*7/16;
7842 }
7843
7844 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(int32_t));
7845 memset(diff[1],0,(x2-x1+3)*3*sizeof(int32_t));
7846 direction=-1;
7847 }
7848 else
7849 {
7850 for(int32_t i=x2-x1; i>=0; --i)
7851 {
7852 mc=((int16_t *)src_bmp->line[0])[i];
7853 mr=getr15(mc);
7854 mg=getg15(mc);
7855 mb=getb15(mc);
7856 cdiff[0]=bound(mr+
7857 diff[0][i][0]+
7858 diff[0][i+1][0]+
7859 diff[0][i+2][0]+
7860 cdiff[0],0,255);
7861 cdiff[1]=bound(mg+
7862 diff[0][i][1]+
7863 diff[0][i+1][1]+
7864 diff[0][i+2][1]+
7865 cdiff[1],0,255);
7866 cdiff[2]=bound(mb+
7867 diff[0][i][2]+
7868 diff[0][i+1][2]+
7869 diff[0][i+2][2]+
7870 cdiff[2],0,255);
7871 // bmp->line[j][i+x1]=bound(makecol8_map(int32_t(cdiff[0]),int32_t(cdiff[1]),int32_t(cdiff[2]),&table),dest_color1,dest_color2);
7872 origcolor=makecol8_map(mr,mg,mb,&table);
7873 // tempcolor=bound(makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table),origcolor-1,origcolor+1);
7874 tempcolor=makecol8_map(cdiff[0],cdiff[1],cdiff[2],&table);
7875 dest_bmp->line[j][i]=tempcolor;
7876 r=getr8(tempcolor);
7877 g=getg8(tempcolor);
7878 b=getb8(tempcolor);
7879 diff[1][i][0]=(cdiff[0]-r)*3/16;
7880 diff[1][i][1]=(cdiff[1]-g)*3/16;
7881 diff[1][i][2]=(cdiff[2]-b)*3/16;
7882 diff[1][i+1][0]=(cdiff[0]-r)*5/16;
7883 diff[1][i+1][1]=(cdiff[1]-g)*5/16;
7884 diff[1][i+1][2]=(cdiff[2]-b)*5/16;
7885 diff[1][i+2][0]=(cdiff[0]-r)*1/16;
7886 diff[1][i+2][1]=(cdiff[1]-g)*1/16;
7887 diff[1][i+2][2]=(cdiff[2]-b)*1/16;
7888 cdiff[0]=(cdiff[0]-r)*7/16;
7889 cdiff[1]=(cdiff[1]-g)*7/16;
7890 cdiff[2]=(cdiff[2]-b)*7/16;
7891 }
7892
7893 memcpy(diff[0],diff[1],(x2-x1+3)*3*sizeof(float));
7894 memset(diff[1],0,(x2-x1+3)*3*sizeof(float));
7895 direction=1;
7896 }
7897 }
7898
7899 blit(dest_bmp, bmp, 0, 0, x1, y1, x2-x1+1, y2-y1+1);
7900 delete[] diff[1];
7901 delete[] diff[0];
7902 destroy_bitmap(src_bmp);
7903 destroy_bitmap(dest_bmp);
7904 return;
7905 }
7906
7907 bool do_text_button(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7908 {
7909 bool over=false;
7910
7911 while(gui_mouse_b())
7912 {
7913 if(mouse_in_rect(x,y,w,h))
7914 {
7915 if(!over)
7916 {
7917 vsync();
7918 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7919 over=true;
7920 update_hw_screen(true);
7921 }
7922 }
7923 else
7924 {
7925 if(over)
7926 {
7927 vsync();
7928 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7929 over=false;
7930 update_hw_screen(true);
7931 }
7932 }
7933 rest(1);
7934 }
7935
7936 return over;
7937 }
7938
7939 bool do_text_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,const char *text)
7940 {
7941 bool over=false;
7942
7943 while(gui_mouse_b())
7944 {
7945 //vsync();
7946 if(mouse_in_rect(x,y,w,h))
7947 {
7948 if(!over)
7949 {
7950 vsync();
7951 jwin_draw_text_button(screen, x, y, w, h, text, D_SELECTED, true);
7952 over=true;
7953
7954 update_hw_screen();
7955 }
7956 }
7957 else
7958 {
7959 if(over)
7960 {
7961 vsync();
7962 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7963 over=false;
7964
7965 update_hw_screen();
7966 }
7967 }
7968 rest(1);
7969 }
7970
7971 if(over)
7972 {
7973 vsync();
7974 jwin_draw_text_button(screen, x, y, w, h, text, 0, true);
7975
7976 update_hw_screen();
7977 }
7978
7979 return over;
7980 }
7981 bool do_icon_button_reset(int32_t x,int32_t y,int32_t w,int32_t h,int icon)
7982 {
7983 bool over=false;
7984
7985 while(gui_mouse_b())
7986 {
7987 //vsync();
7988 if(mouse_in_rect(x,y,w,h))
7989 {
7990 if(!over)
7991 {
7992 vsync();
7993 jwin_draw_icon_button(screen, x, y, w, h, icon, D_SELECTED, true);
7994 over=true;
7995
7996 update_hw_screen();
7997 }
7998 }
7999 else
8000 {
8001 if(over)
8002 {
8003 vsync();
8004 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8005 over=false;
8006
8007 update_hw_screen();
8008 }
8009 }
8010 rest(1);
8011 }
8012
8013 if(over)
8014 {
8015 vsync();
8016 jwin_draw_icon_button(screen, x, y, w, h, icon, 0, true);
8017
8018 update_hw_screen();
8019 }
8020
8021 return over;
8022 }
8023
8024 int32_t jwin_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8025 {
8026 int32_t i;
8027 int32_t tx;
8028 int32_t sd=2; //selected delta
8029 TABPANEL *panel=(TABPANEL *)d->dp;
8030 DIALOG *panel_dialog=NULL, *current_object=NULL;
8031 int32_t selected=0;
8032 int32_t counter=0;
8033 ASSERT(d);
8034 int32_t temp_d, temp_d2;
8035
8036 if(d->dp==NULL) return D_O_K;
8037
8038 panel_dialog=(DIALOG *)d->dp3;
8039
8040 if (msg != MSG_START && msg != MSG_END)
8041 {
8042 bool redraw = false;
8043 for (i = 0; panel[i].text; ++i)
8044 {
8045 if ((panel[i].flags & D_SELECTED) && !(d->flags & D_HIDDEN))
8046 {
8047 for (counter = 0; counter < panel[i].objects; counter++)
8048 {
8049 current_object = panel_dialog + (panel[i].dialog[counter]);
8050 current_object->flags &= ~D_HIDDEN;
8051 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8052 redraw = true;
8053 }
8054 }
8055 else
8056 {
8057 for (counter = 0; counter < panel[i].objects; counter++)
8058 {
8059 current_object = panel_dialog + (panel[i].dialog[counter]);
8060 current_object->flags |= D_HIDDEN;
8061 if (object_message(current_object, MSG_IDLE, 0) & D_REDRAW)
8062 redraw = true;
8063 }
8064 }
8065
8066 /*if (d->flags & D_HIDDEN)
8067 {
8068 for(counter=0; counter<panel[i].objects; counter++)
8069 {
8070 current_object=panel_dialog+(panel[i].dialog[counter]);
8071 current_object->x=zq_screen_w*3;
8072 current_object->y=zq_screen_h*3;
8073 }
8074 }*/
8075 }
8076 if (redraw)
8077 broadcast_dialog_message(MSG_DRAW, 0);
8078 }
8079 FONT *oldfont = font;
8080 switch(msg)
8081 {
8082 case MSG_DRAW:
8083 {
8084 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8085 {
8086 if(d->dp2)
8087 {
8088 font = (FONT *)d->dp2;
8089 }
8090
8091 panel_dialog=(DIALOG *)d->dp3;
8092 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8093 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8094 _allegro_vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8095 _allegro_vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8096 _allegro_vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8097 _allegro_vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8098 _allegro_hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8099 _allegro_hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8100 tx=d->x;
8101
8102 if(d->dp)
8103 {
8104 if(!(panel[((d->d1&0xFF00)>>8)].flags&D_SELECTED))
8105 {
8106 _allegro_hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8107 _allegro_hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8108 }
8109
8110 tx+=2;
8111
8112 for(i=0; panel[i].text; ++i)
8113 {
8114 if(panel[i].flags&D_SELECTED)
8115 {
8116 selected=i;
8117 }
8118 }
8119
8120 for(i=((d->d1&0xFF00)>>8); panel[i].text&&i<=last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w); ++i)
8121 {
8122 sd=(panel[i].flags&D_SELECTED)?0:2;
8123
8124 if((i==((d->d1&0xFF00)>>8)) || (!(panel[i-1].flags&D_SELECTED)))
8125 {
8126 _allegro_vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8127 _allegro_vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8128 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8129 }
8130
8131 _allegro_hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcLIGHT]); //top
8132 _allegro_hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, (char *)panel[i].text), scheme[jcMEDLT]); //top
8133
8134 if(!(panel[i].flags&D_SELECTED))
8135 {
8136 _allegro_hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcLIGHT]); //bottom
8137 _allegro_hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, (char *)panel[i].text)+1, scheme[jcMEDLT]); //bottom
8138 }
8139
8140 tx+=4;
8141 gui_textout_ln(screen, (uint8_t*)panel[i].text, tx+4, d->y+sd+4, scheme[jcBOXFG], scheme[jcBOX], 0);
8142 tx+=text_length(font, (char *)panel[i].text)+10;
8143
8144 if(!(panel[i+1].text) || (!(panel[i+1].flags&D_SELECTED)))
8145 {
8146 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8147 _allegro_vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8148 _allegro_vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8149 }
8150
8151 tx++;
8152 }
8153
8154 if(((d->d1&0xFF00)>>8)!=0||last_visible_tab(panel,((d->d1&0xFF00)>>8),d->w)+1<tab_count(panel))
8155 {
8156 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8157 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8158 }
8159 }
8160
8161 if((tx+(2-sd))<(d->x+d->w))
8162 {
8163 _allegro_hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8164 _allegro_hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8165 }
8166
8167 font = oldfont;
8168
8169 //what dialog is this tab control in (programmer must set manually)
8170 panel_dialog=(DIALOG *)d->dp3;
8171
8172 //for each object handled by the currently selected tab...
8173 for(counter=0; counter<panel[selected].objects; counter++)
8174 {
8175 //assign current_object to one of the controls handled by the tab
8176 current_object=panel_dialog+(panel[selected].dialog[counter]);
8177 //remember the x and y positions of the control
8178 current_object->x=panel[selected].xy[counter*2];
8179 current_object->y=panel[selected].xy[counter*2+1];
8180 object_message(current_object, MSG_DRAW, 0);
8181 }
8182
8183 //if there was a previously selected tab...
8184 if((d->d1&0x00FF)!=0x00FF)
8185 {
8186 //for each object handled by the tab
8187 for(counter=0; counter<panel[d->d1&0xFF].objects; counter++)
8188 {
8189 //assign current_object to one of the controls handled by the tab
8190 current_object=panel_dialog+(panel[d->d1&0xFF].dialog[counter]);
8191 // //remember the x and y positions of the control
8192 // panel[d->d1].xy[counter*2]=current_object->x;
8193 // panel[d->d1].xy[counter*2+1]=current_object->y;
8194 current_object->x=zq_screen_w*3;
8195 current_object->y=zq_screen_h*3;
8196 }
8197 }
8198 }
8199 }
8200 break;
8201
8202 case MSG_CLICK:
8203 {
8204 d->d1&=0xFF00;
8205 d->d1|=0x00FF;
8206 if(d->dp2)
8207 {
8208 font = (FONT *)d->dp2;
8209 }
8210
8211 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8212 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8213 {
8214 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8215 {
8216 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8217 {
8218 temp_d=((d->d1&0xFF00)>>8);
8219 temp_d2=(d->d1&0x00FF);
8220
8221 if(temp_d>0)
8222 {
8223 --temp_d;
8224 }
8225
8226 d->d1=(temp_d<<8)|temp_d2;
8227 d->flags|=D_DIRTY;
8228 }
8229 }
8230 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8231 {
8232 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8233 {
8234 temp_d=((d->d1&0xFF00)>>8);
8235 temp_d2=(d->d1&0x00FF);
8236
8237 if(last_visible_tab(panel, temp_d, d->w)<(tab_count(panel)-1))
8238 {
8239 ++temp_d;
8240 }
8241
8242 d->d1=(temp_d<<8)|temp_d2;
8243 d->flags|=D_DIRTY;
8244 }
8245 }
8246 }
8247 else
8248 {
8249 d_tab_proc(msg, d, c);
8250 }
8251 font = oldfont;
8252 jwin_tab_proc(MSG_IDLE,d,0);
8253 }
8254 break;
8255
8256 default:
8257 return d_tab_proc(msg, d, c);
8258 break;
8259 }
8260
8261 panel_dialog=(DIALOG *)d->dp3;
8262
8263 if(d->flags & D_HIDDEN)
8264 {
8265 for(i=0; panel[i].text; ++i)
8266 {
8267 for(counter=0; counter<panel[i].objects; counter++)
8268 {
8269 current_object=panel_dialog+(panel[i].dialog[counter]);
8270 current_object->x=zq_screen_w*3;
8271 current_object->y=zq_screen_h*3;
8272 }
8273 }
8274
8275 //d->x=zq_screen_w*3;
8276 //d->y=zq_screen_h*3;
8277 }
8278 else
8279 {
8280 for(i=0; panel[i].text; ++i)
8281 {
8282 for(counter=0; counter<panel[i].objects; counter++)
8283 {
8284 current_object=panel_dialog+(panel[i].dialog[counter]);
8285 current_object->x=panel[i].xy[counter*2];
8286 current_object->y=panel[i].xy[counter*2+1];
8287 }
8288 }
8289
8290 // d->x=zq_screen_w*3;
8291 //d->y=zq_screen_h*3;
8292 }
8293
8294 return broadcast_dialog_message(MSG_IDLE, 0);
8295
8296 // return D_O_K;
8297 }
8298
8299 int32_t discern_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t x)
8300 {
8301 int32_t w=0;
8302
8303 for(size_t i=first_tab; i < panel->getSize(); i++)
8304 {
8305 w+=text_length(font, panel->getName(i))+15;
8306
8307 if(w>x)
8308 {
8309 return i;
8310 }
8311 }
8312
8313 return -1;
8314 }
8315 int32_t tabs_width(GUI::TabPanel *panel)
8316 {
8317 int32_t w=0;
8318
8319 for(size_t i=0; i < panel->getSize(); ++i)
8320 {
8321 w+=text_length(font, panel->getName(i))+15;
8322 }
8323
8324 return w+1;
8325 }
8326 bool uses_tab_arrows(GUI::TabPanel *panel, int32_t maxwidth)
8327 {
8328 return (tabs_width(panel)>maxwidth);
8329 }
8330 size_t last_visible_tab(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8331 {
8332 size_t i;
8333 int32_t w=0;
8334
8335 if(uses_tab_arrows(panel, maxwidth))
8336 {
8337 maxwidth-=28;
8338 }
8339
8340 for(i=first_tab; i < panel->getSize(); ++i)
8341 {
8342 w+=text_length(font, panel->getName(i))+15;
8343
8344 if(w>maxwidth)
8345 {
8346 return i-1;
8347 }
8348 }
8349
8350 return i-1;
8351 }
8352 int32_t displayed_tabs_width(GUI::TabPanel *panel, int32_t first_tab, int32_t maxwidth)
8353 {
8354 size_t i=0;
8355 int32_t w=0;
8356
8357 for(i=first_tab; i<=last_visible_tab(panel, first_tab, maxwidth); ++i)
8358 {
8359 w+=text_length(font, panel->getName(i))+15;
8360 }
8361
8362 return w+1;
8363 }
8364
8365 INLINE int32_t is_in_rect(int32_t x,int32_t y,int32_t rx1,int32_t ry1,int32_t rx2,int32_t ry2)
8366 {
8367 return x>=rx1 && x<=rx2 && y>=ry1 && y<=ry2;
8368 }
8369
8370 int32_t new_tab_proc(int32_t msg, DIALOG *d, int32_t c)
8371 {
8372 assert(d->flags&D_NEW_GUI);
8373
8374 int32_t tx;
8375 int32_t ret = D_O_K;
8376 int32_t sd=2; //selected delta
8377 static bool skipredraw = false;
8378 GUI::TabPanel *panel=(GUI::TabPanel*)d->dp;
8379 ASSERT(d);
8380
8381 if(d->dp==NULL) return D_O_K;
8382
8383 FONT *oldfont = font;
8384 if(d->dp2)
8385 {
8386 font = (FONT *)d->dp2;
8387 }
8388
8389 switch(msg)
8390 {
8391 case MSG_DRAW:
8392 {
8393 if(skipredraw)
8394 {
8395 skipredraw = false;
8396 ret = D_REDRAW;
8397 break;
8398 }
8399 if(d->x<zq_screen_w&&d->y<zq_screen_h)
8400 {
8401 rectfill(screen, d->x, d->y, d->x+d->w-1, d->y+8+text_height(font), scheme[jcBOX]); //tab area
8402 rectfill(screen, d->x+1, d->y+sd+text_height(font)+7, d->x+d->w-2, d->y+sd+d->h-2, scheme[jcBOX]); //panel
8403 _allegro_vline(screen, d->x, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcLIGHT]);
8404 _allegro_vline(screen, d->x+1, d->y+sd+7+text_height(font), d->y+sd+d->h-3, scheme[jcMEDLT]);
8405 _allegro_vline(screen, d->x+d->w-2, d->y+sd+7+text_height(font), d->y+sd+d->h-2, scheme[jcMEDDARK]);
8406 _allegro_vline(screen, d->x+d->w-1, d->y+sd+7+text_height(font)-1, d->y+sd+d->h-1, scheme[jcDARK]);
8407 _allegro_hline(screen, d->x+1, d->y+sd+d->h-2, d->x+d->w-3, scheme[jcMEDDARK]);
8408 _allegro_hline(screen, d->x, d->y+sd+d->h-1, d->x+d->w-2, scheme[jcDARK]);
8409 tx=d->x;
8410
8411 if(d->dp)
8412 {
8413 if(panel->getCurrentIndex() != d->d1)
8414 {
8415 _allegro_hline(screen, tx+1, d->y+sd+6+text_height(font)+1, tx+2, scheme[jcMEDLT]); //initial bottom
8416 _allegro_hline(screen, tx, d->y+sd+6+text_height(font), tx+1, scheme[jcLIGHT]); //initial bottom
8417 }
8418
8419 tx+=2;
8420
8421 for(size_t i=d->d1; i < panel->getSize()&&i<=last_visible_tab(panel,d->d1,d->w); ++i)
8422 {
8423 sd=(i==panel->getCurrentIndex())?0:2;
8424
8425 if((i==d->d1) || (i-1 != panel->getCurrentIndex()))
8426 {
8427 _allegro_vline(screen, tx-(2-sd), d->y+sd+2, d->y+8+text_height(font), scheme[jcLIGHT]); //left side
8428 _allegro_vline(screen, tx-(2-sd)+1, d->y+sd+2, d->y+8+text_height(font), scheme[jcMEDLT]); //left side
8429 putpixel(screen, tx+1-(2-sd), d->y+sd+1, scheme[jcLIGHT]); //left angle
8430 }
8431
8432 _allegro_hline(screen, tx+2-(2-sd), d->y+sd, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcLIGHT]); //top
8433 _allegro_hline(screen, tx+2-(2-sd), d->y+sd+1, tx+12+(2-sd)+text_length(font, panel->getName(i)), scheme[jcMEDLT]); //top
8434
8435 if(i!=panel->getCurrentIndex())
8436 {
8437 _allegro_hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcLIGHT]); //bottom
8438 _allegro_hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcMEDLT]); //bottom
8439 }
8440 else if(d->flags & D_GOTFOCUS)
8441 {
8442 _allegro_hline(screen, tx+1, d->y+sd+6+text_height(font), tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8443 _allegro_hline(screen, tx, d->y+sd+6+text_height(font)+1, tx+13+text_length(font, panel->getName(i))+1, scheme[jcBOXFG]); //bottom
8444 }
8445
8446 tx+=4;
8447 uint8_t* pname = (uint8_t*)(panel->getName(i));
8448 bool dis = panel->getDisabled(i);
8449 if(dis)
8450 gui_textout_ln(screen, pname, tx+5, d->y+sd+5, scheme[jcLIGHT], scheme[jcBOX], 0);
8451 gui_textout_ln(screen, pname, tx+4, d->y+sd+4, scheme[dis ? jcDISABLED_FG : jcBOXFG], dis ? -1 : scheme[jcBOX], 0);
8452 tx+=text_length(font, (const char*)pname)+10;
8453
8454 if((i+1>=panel->getSize()) || (i+1!=panel->getCurrentIndex()))
8455 {
8456 putpixel(screen, tx-1+(2-sd), d->y+sd+1, scheme[jcDARK]); //right angle
8457 _allegro_vline(screen, tx+(2-sd), d->y+sd+2, d->y+8+text_height(font)-1, scheme[jcDARK]); //right side
8458 _allegro_vline(screen, tx+(2-sd)-1, d->y+sd+2, d->y+8+text_height(font)-(sd?1:0), scheme[jcMEDDARK]); //right side
8459 }
8460
8461 tx++;
8462 }
8463
8464 if(d->d1!=0||last_visible_tab(panel,d->d1,d->w)+1<panel->getSize())
8465 {
8466 jwin_draw_icon_button(screen,d->x+d->w-14,d->y+2, 14, 14, BTNICON_ARROW_RIGHT, 0, true);
8467 jwin_draw_icon_button(screen,d->x+d->w-28,d->y+2, 14, 14, BTNICON_ARROW_LEFT, 0, true);
8468 }
8469 }
8470
8471 if((tx+(2-sd))<(d->x+d->w))
8472 {
8473 _allegro_hline(screen, tx+(2-sd)-1, d->y+8+text_height(font), d->x+d->w-1, scheme[jcLIGHT]); //ending bottom
8474 _allegro_hline(screen, tx+(2-sd)-2, d->y+8+text_height(font)+1, d->x+d->w-2, scheme[jcMEDLT]); //ending bottom
8475 }
8476
8477 }
8478 }
8479 break;
8480
8481 case MSG_WANTFOCUS:
8482 // if(gui_mouse_b())
8483 ret = D_WANTFOCUS|D_REDRAW;
8484 break;
8485 case MSG_GOTFOCUS:
8486 case MSG_LOSTFOCUS:
8487 skipredraw = true;
8488 break;
8489 case MSG_CHAR:
8490 {
8491 int32_t ind = panel->getCurrentIndex();
8492 auto oldind = ind;
8493 switch(c>>8)
8494 {
8495 case KEY_LEFT:
8496 do
8497 {
8498 if(ind > 0)
8499 {
8500 --ind;
8501 }
8502 else
8503 {
8504 ind = panel->getSize()-1;
8505 }
8506 }
8507 while(ind != oldind && panel->getDisabled(ind));
8508 break;
8509 case KEY_RIGHT:
8510 do
8511 {
8512 if(ind+1 < signed(panel->getSize()))
8513 {
8514 ++ind;
8515 }
8516 else
8517 {
8518 ind = 0;
8519 }
8520 }
8521 while(ind != oldind && panel->getDisabled(ind));
8522 break;
8523 default: ind = -1;
8524 }
8525 if(ind > -1 && ind != oldind)
8526 {
8527 panel->switchTo(ind);
8528 GUI_EVENT(d, geCHANGE_SELECTION);
8529 ret |= D_USED_CHAR;
8530 }
8531 }
8532 break;
8533
8534 case MSG_CLICK:
8535 {
8536 // is the mouse on one of the tab arrows (if visible) or in the tab area?
8537 if(uses_tab_arrows(panel, d->w)&&(mouse_in_rect(d->x+d->w-28, d->y+2, 28, 14)))
8538 {
8539 if(mouse_in_rect(d->x+d->w-28, d->y+2, 14, 14))
8540 {
8541 if(do_icon_button_reset(d->x+d->w-28, d->y+2, 14, 14, BTNICON_ARROW_LEFT))
8542 {
8543 if(d->d1>0)
8544 {
8545 --d->d1;
8546 }
8547
8548 ret |= D_REDRAW;
8549 }
8550 }
8551 else if(mouse_in_rect(d->x+d->w-14, d->y+2, 14, 14))
8552 {
8553 if(do_icon_button_reset(d->x+d->w-14, d->y+2, 14, 14, BTNICON_ARROW_RIGHT))
8554 {
8555 size_t t = last_visible_tab(panel, d->d1, d->w);
8556 if(t<(panel->getSize()-1))
8557 {
8558 while(t==last_visible_tab(panel, d->d1, d->w))
8559 ++d->d1;
8560 }
8561
8562 ret |= D_REDRAW;
8563 }
8564 }
8565 }
8566 else if(is_in_rect(gui_mouse_x(),gui_mouse_y(), d->x+2, d->y+2, d->x+displayed_tabs_width(panel,((d->d1&0xFF00)>>8),d->w), d->y+text_height(font)+9))
8567 {
8568 // find out what the new tab (tb) will be (where the mouse is)
8569 int32_t newtab = discern_tab(panel, d->d1, gui_mouse_x()-d->x-2);
8570 if(newtab > -1 && newtab != panel->getCurrentIndex() && !panel->getDisabled(newtab))
8571 {
8572 panel->switchTo(newtab);
8573 GUI_EVENT(d, geCHANGE_SELECTION);
8574 }
8575 }
8576 }
8577 break;
8578 }
8579 font = oldfont;
8580 return ret;
8581 }
8582
8583
8584
8585
8586 int32_t jwin_hline_proc(int32_t msg, DIALOG *d, int32_t)
8587 {
8588 ASSERT(d);
8589
8590 if(msg==MSG_DRAW)
8591 {
8592 if(d->w < 1) return D_O_K;
8593 for(int q = 0; q <= d->d1; ++q)
8594 {
8595 if(d->d2&1)
8596 {
8597 _allegro_hline(screen, d->x, d->y+q, d->x+d->w-1, d->fg);
8598 }
8599 else
8600 {
8601 _allegro_hline(screen, d->x, d->y-q, d->x+d->w-1, scheme[jcMEDDARK]);
8602 _allegro_hline(screen, d->x, d->y+1+q, d->x+d->w-1, scheme[jcLIGHT]);
8603 }
8604 }
8605 }
8606
8607 return D_O_K;
8608 }
8609
8610 int32_t jwin_vline_proc(int32_t msg, DIALOG *d, int32_t)
8611 {
8612 ASSERT(d);
8613
8614 if(msg==MSG_DRAW)
8615 {
8616 if(d->h < 1) return D_O_K;
8617 for(int q = 0; q <= d->d1; ++q)
8618 {
8619 if(d->d2&1)
8620 {
8621 _allegro_vline(screen, d->x+q, d->y, d->y+d->h-1, d->fg);
8622 }
8623 else
8624 {
8625 _allegro_vline(screen, d->x+q, d->y, d->y+d->h-1, scheme[jcMEDDARK]);
8626 _allegro_vline(screen, d->x+1-q, d->y, d->y+d->h-1, scheme[jcLIGHT]);
8627 }
8628 }
8629 }
8630
8631 return D_O_K;
8632 }
8633
8634 int32_t jwin_editbox_proc(int32_t msg, DIALOG *d, int32_t c)
8635 {
8636 return d_editbox_proc(msg, d, c);
8637 }
8638
8639 //centers dialog based on first object, which should be the containing window
8640 3480 void jwin_center_dialog(DIALOG *dialog)
8641 {
8642 int32_t xc, yc;
8643 int32_t c;
8644 ASSERT(dialog);
8645
8646 /* how much to move by? */
8647 3480 xc = (zq_screen_w - dialog[0].w) / 2 - dialog[0].x;
8648 3480 yc = (zq_screen_h - dialog[0].h) / 2 - dialog[0].y;
8649
8650 /* move it */
8651
2/2
✓ Branch 0 taken 77284 times.
✓ Branch 1 taken 3480 times.
80764 for(c=0; dialog[c].proc; c++)
8652 {
8653 77284 dialog[c].x += xc;
8654 77284 dialog[c].y += yc;
8655 77284 }
8656 3480 }
8657 //up-left aligns dialog based on first object, which should be the containing window
8658 void jwin_ulalign_dialog(DIALOG *dialog)
8659 {
8660 int32_t xc, yc;
8661 int32_t c;
8662 ASSERT(dialog);
8663
8664 /* how much to move by? */
8665 xc = dialog[0].x;
8666 yc = dialog[0].y;
8667
8668 /* move it */
8669 for(c=0; dialog[c].proc; c++)
8670 {
8671 dialog[c].x -= xc;
8672 dialog[c].y -= yc;
8673 }
8674 }
8675
8676 //Custom slider proc
8677 int32_t d_jslider_proc(int32_t msg, DIALOG *d, int32_t c)
8678 {
8679 BITMAP *gui_bmp = screen;
8680 BITMAP *slhan = NULL;
8681 int32_t oldpos, newpos;
8682 int32_t sfg; /* slider foreground color */
8683 int32_t vert = TRUE; /* flag: is slider vertical? */
8684 int32_t hh = 7; /* handle height (width for horizontal sliders) */
8685 int32_t hmar; /* handle margin */
8686 int32_t slp; /* slider position */
8687 int32_t mp; /* mouse position */
8688 int32_t irange;
8689 int32_t slx, sly, slh, slw;
8690 int32_t msx, msy;
8691 int32_t retval = D_O_K;
8692 int32_t upkey, downkey;
8693 int32_t pgupkey, pgdnkey;
8694 int32_t homekey, endkey;
8695 int32_t delta;
8696 fixed slratio, slmax, slpos;
8697 typedef int32_t (*SLIDER_TYPE)(void*, int32_t);
8698 SLIDER_TYPE proc = NULL;
8699 //int32_t (*proc)(void *cbpointer, int32_t d2value);
8700 int32_t oldval;
8701 ASSERT(d);
8702
8703 /* check for slider direction */
8704 if(d->h < d->w)
8705 vert = FALSE;
8706
8707 /* set up the metrics for the control */
8708 if(d->dp != NULL)
8709 {
8710 slhan = (BITMAP *)d->dp;
8711
8712 if(vert)
8713 hh = slhan->h;
8714 else
8715 hh = slhan->w;
8716 }
8717
8718 hmar = hh/2;
8719 irange = (vert) ? d->h : d->w;
8720 slmax = itofix(irange-hh);
8721 slratio = slmax / (d->d1);
8722 slpos = slratio * d->d2;
8723 slp = fixtoi(slpos);
8724
8725 switch(msg)
8726 {
8727
8728 case MSG_DRAW:
8729 sfg = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8730
8731 if(vert)
8732 {
8733 rectfill(gui_bmp, d->x, d->y, d->x+d->w/2-2, d->y+d->h-1, d->bg);
8734 rectfill(gui_bmp, d->x+d->w/2-1, d->y, d->x+d->w/2+1, d->y+d->h-1, sfg);
8735 rectfill(gui_bmp, d->x+d->w/2+2, d->y, d->x+d->w-1, d->y+d->h-1, d->bg);
8736 }
8737 else
8738 {
8739 rectfill(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h/2-2, d->bg);
8740 rectfill(gui_bmp, d->x, d->y+d->h/2-1, d->x+d->w-1, d->y+d->h/2+1, sfg);
8741 rectfill(gui_bmp, d->x, d->y+d->h/2+2, d->x+d->w-1, d->y+d->h-1, d->bg);
8742 }
8743
8744 /* okay, background and slot are drawn, now draw the handle */
8745 if(slhan)
8746 {
8747 if(vert)
8748 {
8749 slx = d->x+(d->w/2)-(slhan->w/2);
8750 sly = d->y+(d->h-1)-(hh+slp);
8751 }
8752 else
8753 {
8754 slx = d->x+slp;
8755 sly = d->y+(d->h/2)-(slhan->h/2);
8756 }
8757
8758 draw_sprite(gui_bmp, slhan, slx, sly);
8759 }
8760 else
8761 {
8762 /* draw default handle */
8763 if(vert)
8764 {
8765 slx = d->x;
8766 sly = d->y+(d->h)-(hh+slp);
8767 slw = d->w-1;
8768 slh = hh-1;
8769 }
8770 else
8771 {
8772 slx = d->x+slp;
8773 sly = d->y;
8774 slw = hh-1;
8775 slh = d->h-1;
8776 }
8777
8778 /* draw body */
8779 rectfill(gui_bmp, slx+2, sly, slx+(slw-2), sly+slh, sfg);
8780 vline(gui_bmp, slx+1, sly+1, sly+slh-1, sfg);
8781 vline(gui_bmp, slx+slw-1, sly+1, sly+slh-1, sfg);
8782 vline(gui_bmp, slx, sly+2, sly+slh-2, sfg);
8783 vline(gui_bmp, slx+slw, sly+2, sly+slh-2, sfg);
8784 vline(gui_bmp, slx+1, sly+2, sly+slh-2, d->bg);
8785 hline(gui_bmp, slx+2, sly+1, slx+slw-2, d->bg);
8786 putpixel(gui_bmp, slx+2, sly+2, d->bg);
8787 }
8788
8789 if(d->flags & D_GOTFOCUS)
8790 dotted_rect(gui_bmp, d->x, d->y, d->x+d->w-1, d->y+d->h-1, sfg, d->bg);
8791
8792 break;
8793
8794 case MSG_WANTFOCUS:
8795 case MSG_LOSTFOCUS:
8796 return D_WANTFOCUS;
8797
8798 case MSG_KEY:
8799 if(!(d->flags & D_GOTFOCUS))
8800 return D_WANTFOCUS;
8801 else
8802 return D_O_K;
8803
8804 case MSG_CHAR:
8805 /* handle movement keys to move slider */
8806 c >>= 8;
8807
8808 if(vert)
8809 {
8810 upkey = KEY_UP;
8811 downkey = KEY_DOWN;
8812 pgupkey = KEY_PGUP;
8813 pgdnkey = KEY_PGDN;
8814 homekey = KEY_END;
8815 endkey = KEY_HOME;
8816 }
8817 else
8818 {
8819 upkey = KEY_RIGHT;
8820 downkey = KEY_LEFT;
8821 pgupkey = KEY_PGDN;
8822 pgdnkey = KEY_PGUP;
8823 homekey = KEY_HOME;
8824 endkey = KEY_END;
8825 }
8826
8827 if(c == upkey)
8828 delta = 1;
8829 else if(c == downkey)
8830 delta = -1;
8831 else if(c == pgdnkey)
8832 delta = -d->d1 / 16;
8833 else if(c == pgupkey)
8834 delta = d->d1 / 16;
8835 else if(c == homekey)
8836 delta = -d->d2;
8837 else if(c == endkey)
8838 delta = d->d1 - d->d2;
8839 else
8840 delta = 0;
8841
8842 if(delta)
8843 {
8844 oldpos = slp;
8845 oldval = d->d2;
8846
8847 //while (true) {
8848 for(; ;) //thank you, MSVC ~pkmnfrk
8849 {
8850 d->d2 = d->d2+delta;
8851 slpos = slratio*d->d2;
8852 slp = fixtoi(slpos);
8853
8854 if((slp != oldpos) || (d->d2 <= 0) || (d->d2 >= d->d1))
8855 break;
8856 }
8857
8858 if(d->d2 < 0)
8859 d->d2 = 0;
8860
8861 if(d->d2 > d->d1)
8862 d->d2 = d->d1;
8863
8864 retval = D_USED_CHAR;
8865
8866 if(d->d2 != oldval)
8867 {
8868 /* call callback function here */
8869 if(d->dp2)
8870 {
8871 proc = (SLIDER_TYPE)(d->dp2);
8872 retval |= (*proc)(d->dp3, d->d2);
8873 }
8874
8875 GUI_EVENT(d, geCHANGE_VALUE);
8876
8877 object_message(d, MSG_DRAW, 0);
8878 }
8879 }
8880
8881 break;
8882
8883 case MSG_WANTWHEEL:
8884 return 1;
8885
8886 case MSG_WHEEL:
8887 oldval = d->d2;
8888 d->d2 = MID(0, d->d2+c, d->d1);
8889
8890 if(d->d2 != oldval)
8891 {
8892 /* call callback function here */
8893 if(d->dp2)
8894 {
8895 proc = (SLIDER_TYPE)(d->dp2);
8896 retval |= (*proc)(d->dp3, d->d2);
8897 }
8898
8899 GUI_EVENT(d, geCHANGE_VALUE);
8900 object_message(d, MSG_DRAW, 0);
8901 retval |= D_REDRAWME;
8902 }
8903
8904 break;
8905
8906 case MSG_CLICK:
8907 /* track the mouse until it is released */
8908 mp = slp;
8909
8910 while(gui_mouse_b())
8911 {
8912 msx = gui_mouse_x();
8913 msy = gui_mouse_y();
8914 oldval = d->d2;
8915
8916 if(vert)
8917 mp = (d->y+d->h-hmar)-msy;
8918 else
8919 mp = msx-(d->x+hmar);
8920
8921 if(mp < 0)
8922 mp = 0;
8923
8924 if(mp > irange-hh)
8925 mp = irange-hh;
8926
8927 slpos = itofix(mp);
8928 slmax = fixdiv(slpos, slratio);
8929 newpos = fixtoi(slmax);
8930
8931 if(newpos != oldval)
8932 {
8933 d->d2 = newpos;
8934
8935 /* call callback function here */
8936 if(d->dp2 != NULL)
8937 {
8938 proc = (SLIDER_TYPE)(d->dp2);
8939 retval |= (*proc)(d->dp3, d->d2);
8940 }
8941
8942 GUI_EVENT(d, geCHANGE_VALUE);
8943 object_message(d, MSG_DRAW, 0);
8944 }
8945
8946 /* let other objects continue to animate */
8947 broadcast_dialog_message(MSG_IDLE, 0);
8948 update_hw_screen();
8949 }
8950
8951 break;
8952 }
8953
8954 return retval;
8955 }
8956
8957 // This is only used by jwin_check_proc and jwin_radio_proc.
8958 int32_t d_jwinbutton_proc(int32_t msg, DIALOG *d, int32_t)
8959 {
8960 BITMAP *gui_bmp;
8961 int32_t state1, state2;
8962 int32_t black;
8963 int32_t swap;
8964 int32_t g;
8965 ASSERT(d);
8966
8967 gui_bmp = screen;
8968
8969 switch(msg)
8970 {
8971 case MSG_DRAW:
8972 {
8973 if(d->flags & D_SELECTED)
8974 {
8975 g = 1;
8976 state1 = d->bg;
8977 state2 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8978 }
8979 else
8980 {
8981 g = 0;
8982 state1 = (d->flags & D_DISABLED) ? scheme[jcDISABLED_FG] : d->fg;
8983 state2 = d->bg;
8984 }
8985
8986 rectfill(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state2);
8987 rect(gui_bmp, d->x+g, d->y+g, d->x+d->w-2+g, d->y+d->h-2+g, state1);
8988 gui_textout_ex(gui_bmp, (char *)d->dp, d->x+d->w/2+g, d->y+d->h/2-text_height(font)/2+g, state1, -1, TRUE);
8989
8990 if(d->flags & D_SELECTED)
8991 {
8992 vline(gui_bmp, d->x, d->y, d->y+d->h-2, d->bg);
8993 hline(gui_bmp, d->x, d->y, d->x+d->w-2, d->bg);
8994 }
8995 else
8996 {
8997 black = makecol(0,0,0);
8998 vline(gui_bmp, d->x+d->w-1, d->y+1, d->y+d->h-2, black);
8999 hline(gui_bmp, d->x+1, d->y+d->h-1, d->x+d->w-1, black);
9000 }
9001
9002 if((d->flags & D_GOTFOCUS) &&
9003 (!(d->flags & D_SELECTED) || !(d->flags & D_EXIT)))
9004 dotted_rect(gui_bmp, d->x+1+g, d->y+1+g, d->x+d->w-3+g, d->y+d->h-3+g, state1, state2);
9005
9006 break;
9007 }
9008 case MSG_WANTFOCUS:
9009 return D_WANTFOCUS;
9010
9011 case MSG_KEY:
9012 {
9013 /* close dialog? */
9014 if(d->flags & D_EXIT)
9015 {
9016 return D_CLOSE;
9017 }
9018
9019 /* or just toggle */
9020 d->flags ^= D_SELECTED;
9021 GUI_EVENT(d, geTOGGLE);
9022 object_message(d, MSG_DRAW, 0);
9023 break;
9024 }
9025
9026 case MSG_CLICK:
9027 {
9028 /* what state was the button originally in? */
9029 state1 = d->flags & D_SELECTED;
9030
9031 swap = state1;
9032
9033 /* track the mouse until it is released */
9034 while(gui_mouse_b())
9035 {
9036 state2 = ((gui_mouse_x() >= d->x) && (gui_mouse_y() >= d->y) &&
9037 (gui_mouse_x() < d->x + d->w) && (gui_mouse_y() < d->y + d->h));
9038
9039 if(swap)
9040 state2 = !state2;
9041
9042 /* redraw? */
9043 bool should_redraw = false;
9044 if(((state1) && (!state2)) || ((state2) && (!state1)))
9045 {
9046 d->flags ^= D_SELECTED;
9047 GUI_EVENT(d, geTOGGLE);
9048 state1 = d->flags & D_SELECTED;
9049 object_message(d, MSG_DRAW, 0);
9050 should_redraw = true;
9051 }
9052
9053 /* let other objects continue to animate */
9054 int r = broadcast_dialog_message(MSG_IDLE, 0);
9055 if (r & D_REDRAWME) should_redraw = true;
9056
9057 if (should_redraw)
9058 {
9059 update_hw_screen();
9060 }
9061 }
9062
9063 if(d->dp3 != NULL)
9064 {
9065 //object_message(d, MSG_DRAW, 0);
9066 typedef int32_t (*funcType)(void);
9067 funcType func=reinterpret_cast<funcType>(d->dp3);
9068
9069 return func();
9070 }
9071
9072 /* should we close the dialog? */
9073 if(d->flags & D_EXIT)
9074 {
9075 return D_CLOSE;
9076 }
9077 break;
9078 }
9079 }
9080
9081 return D_O_K;
9082 }
9083
9084 //Misc bitmap drawing
9085 void draw_x(BITMAP* dest, int x1, int y1, int x2, int y2, int color)
9086 {
9087 line(dest, x1, y1, x2, y2, color);
9088 line(dest, x1, y2, x2, y1, color);
9089 }
9090
9091 void draw_check(BITMAP* dest, int x1, int y1, int x2, int y2, int c)
9092 {
9093 if(x2 < x1)
9094 zc_swap(x2,x1);
9095 if(y2 < y1)
9096 zc_swap(y2,y1);
9097 int x3 = ((x2-x1)/2)+x1;
9098 int y3 = y2-(x3-x1);
9099 line(dest, x1, y3, x3, y2, c);
9100 line(dest, x3, y2, x2, y1, c);
9101 }
9102
9103 void draw_checkerboard(BITMAP* dest, int x, int y, int sz, optional<int> cb_sz, int offx, int offy)
9104 {
9105 if(!cb_sz)
9106 cb_sz = sz/2;
9107 int ox = -x+offx, oy = -y+offy;
9108 ditherrectfill(dest, x, y, x+sz-1, y+sz-1, vc(CheckerCol1), dithChecker, *cb_sz, ox, oy, vc(CheckerCol2));
9109 }
9110
9111 int32_t d_vsync_proc(int32_t msg,DIALOG *d,int32_t c)
9112 {
9113 static std::chrono::steady_clock::time_point tics;
9114 auto now = std::chrono::steady_clock::now();
9115
9116 switch(msg)
9117 {
9118 case MSG_START:
9119 tics = std::chrono::steady_clock::now();
9120 break;
9121
9122 case MSG_IDLE:
9123 {
9124 int num_vsyncs = 0;
9125 while (now - tics >= std::chrono::milliseconds(1000/60))
9126 {
9127 tics += std::chrono::milliseconds(1000/60);
9128 broadcast_dialog_message(MSG_VSYNC, c);
9129 if(d->dp)
9130 {
9131 int32_t ret = (*(std::function<int32_t()>*)d->dp)();
9132 switch(ret)
9133 {
9134 case ONTICK_EXIT:
9135 if(d->flags&D_NEW_GUI)
9136 close_new_gui_dlg(d);
9137 return D_EXIT;
9138 case ONTICK_CLOSE:
9139 if(d->flags&D_NEW_GUI)
9140 {
9141 //Simulate a GUI_EVENT for the window proc
9142 DIALOG* window = d-1;
9143 while(window->proc != jwin_win_proc) --window;
9144 int32_t ret = new_gui_event(window-1, geCLOSE);
9145 if(ret >= 0)
9146 return ret;
9147 }
9148 return D_EXIT;
9149 case ONTICK_REDRAW:
9150 return D_REDRAW;
9151 }
9152 }
9153
9154 if (++num_vsyncs == 3) break;
9155 }
9156 break;
9157 }
9158 }
9159
9160 return D_O_K;
9161 }
9162
9163 //
9164
9165 void draw_checkbox(BITMAP *dest,int x,int y,int sz,bool value)
9166 {
9167 draw_checkbox(dest,x,y,sz,sz,value);
9168 }
9169 void draw_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9170 {
9171 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9172 rectfill(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTBG]);
9173
9174 if(value)
9175 {
9176 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9177 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9178 }
9179 }
9180 void draw_dis_checkbox(BITMAP *dest,int x,int y,int wid,int hei,bool value)
9181 {
9182 jwin_draw_frame(dest, x, y, wid, hei, FR_DEEP);
9183
9184 if(value)
9185 {
9186 line(dest, x+2, y+2, x+wid-3, y+hei-3, jwin_pal[jcTEXTFG]);
9187 line(dest, x+2, y+hei-3, x+wid-3, y+2, jwin_pal[jcTEXTFG]);
9188 }
9189 }
9190
9191 bool do_scheckbox(BITMAP *dest,int x,int y,int sz,int &value, int xoffs, int yoffs)
9192 {
9193 return do_checkbox(dest,x,y,sz,sz,value,xoffs,yoffs);
9194 }
9195 bool do_checkbox(BITMAP *dest,int x,int y,int wid,int hei,int &value, int xoffs, int yoffs)
9196 {
9197 bool over=false;
9198
9199 while(gui_mouse_b())
9200 {
9201 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1,y+hei-1))
9202 {
9203 if(!over)
9204 {
9205 value=value?0:1;
9206 draw_checkbox(dest,x,y,wid,hei,value!=0);
9207 over=true;
9208 update_hw_screen(true);
9209 }
9210 }
9211 else
9212 {
9213 if(over)
9214 {
9215 value=value?0:1;
9216 draw_checkbox(dest,x,y,wid,hei,value!=0);
9217 over=false;
9218 update_hw_screen(true);
9219 }
9220 }
9221 rest(1);
9222 }
9223
9224 return over;
9225 }
9226 bool do_checkbox_tx(BITMAP *dest,int x,int y,int wid,int hei,int &value, int txtoffs, int xoffs, int yoffs)
9227 {
9228 bool over=false;
9229
9230 while(gui_mouse_b())
9231 {
9232 if(isinRect(gui_mouse_x()-xoffs,gui_mouse_y()-yoffs,x,y,x+wid-1+txtoffs,y+hei-1))
9233 {
9234 if(!over)
9235 {
9236 value=value?0:1;
9237 draw_checkbox(dest,x,y,wid,hei,value!=0);
9238 over=true;
9239 update_hw_screen(true);
9240 }
9241 }
9242 else
9243 {
9244 if(over)
9245 {
9246 value=value?0:1;
9247 draw_checkbox(dest,x,y,wid,hei,value!=0);
9248 over=false;
9249 update_hw_screen(true);
9250 }
9251 }
9252 rest(1);
9253 }
9254
9255 return over;
9256 }
9257
9258 //box_out stuff
9259 static int32_t box_x = 0;
9260 static int32_t box_y = 0;
9261 static bool box_active=false;
9262 static int32_t box_store_x = 0;
9263 358 static FONT *box_title_font=font;
9264 358 static FONT *box_message_font=font;
9265 static int32_t box_style=0;
9266 static int32_t box_titlebar_height=0;
9267 static int32_t box_message_height=0;
9268 static uint8_t box_text_scale=1;
9269 static int32_t box_w=304;
9270 static int32_t box_h=176;
9271 static int32_t box_l=8;
9272 static int32_t box_r=312;
9273 static int32_t box_t=32;
9274 static int32_t box_b=208;
9275 static bool box_log=true;
9276 static char box_log_msg[480];
9277 static int32_t box_msg_pos=0;
9278 static int32_t box_store_pos=0;
9279
9280 int32_t onSnapshot2()
9281 {
9282 char buf[20];
9283 int32_t num=0;
9284
9285 do
9286 {
9287 sprintf(buf, "zelda%03d.bmp", ++num);
9288 }
9289 while(num<999 && exists(buf));
9290
9291 PALETTE temppal;
9292 get_palette(temppal);
9293 BITMAP *tempbmp=create_bitmap_ex(8,screen->w, screen->h);
9294 blit(screen,tempbmp,0,0,0,0,screen->w,screen->h);
9295 save_bitmap(buf,screen,temppal);
9296 destroy_bitmap(tempbmp);
9297 return D_O_K;
9298 }
9299
9300 void set_default_box_size()
9301 {
9302 int32_t screen_w = screen->w;
9303 int32_t screen_h = screen->h;
9304
9305 box_w=MIN(512, screen_w-16);
9306 box_h=MIN(256, (screen_h-64)&0xFFF0);
9307
9308 box_l=(screen_w-box_w)/2;
9309 box_t=(screen_h-box_h)/2;
9310 box_r=box_l+box_w;
9311 box_b=box_t+box_h;
9312 }
9313 /* resizes the box */
9314 void set_box_size(int32_t w, int32_t h)
9315 {
9316 int32_t screen_w = zq_screen_w;
9317 int32_t screen_h = zq_screen_h;
9318
9319 if(w <= 0) w = 512;
9320 if(h <= 0) h = 256;
9321 box_w=MIN(w, screen_w-16);
9322 box_h=MIN(h, (screen_h-64)&0xFFF0);
9323
9324 box_l=(screen_w-box_w)/2;
9325 box_t=(screen_h-box_h)/2;
9326 box_r=box_l+box_w;
9327 box_b=box_t+box_h;
9328 }
9329
9330 /* starts outputting a progress message */
9331 6 void box_start(int32_t style, const char *title, FONT *title_font, FONT *message_font, bool log, int32_t w, int32_t h, uint8_t scale)
9332 {
9333
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (is_headless())
9334 6 return;
9335
9336 box_text_scale=scale;
9337 box_style=style;
9338 box_title_font=(title_font!=NULL)?title_font:font;
9339 box_message_font=(message_font!=NULL)?message_font:font;
9340 box_message_height=text_height(box_message_font)*scale;
9341 box_titlebar_height=title?text_height(box_title_font)+2:0;
9342 set_box_size(w,h);
9343 /*
9344 box_w=BOX_W;
9345 box_h=BOX_H;
9346 box_l=BOX_L;
9347 box_r=BOX_R;
9348 box_t=BOX_T;
9349 box_b=BOX_B;
9350 */
9351 box_log=log;
9352 memset(box_log_msg, 0, 480);
9353 box_msg_pos=0;
9354 box_store_pos=0;
9355
9356 if(!box_active)
9357 popup_zqdialog_start();
9358 jwin_draw_win(screen, box_l, box_t, box_r-box_l, box_b-box_t, FR_WIN);
9359
9360 if(title!=NULL)
9361 {
9362 zc_swap(font,box_title_font);
9363 jwin_draw_titlebar(screen, box_l+3, box_t+3, box_r-box_l-6, 18, title, false);
9364 zc_swap(font,box_title_font);
9365 box_titlebar_height=18;
9366 }
9367
9368
9369 box_store_x = box_x = box_y = 0;
9370 box_active = true;
9371 box_t+=box_titlebar_height;
9372 box_h-=box_titlebar_height;
9373 box_log=log;
9374 memset(box_log_msg, 0, 480);
9375 box_msg_pos=0;
9376 box_store_pos=0;
9377 6 }
9378
9379 /* outputs text to the progress message */
9380 36179 void box_out(const char *msg)
9381 {
9382
1/2
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
36179 string remainder = "";
9383
1/2
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
36179 string temp(msg);
9384
9385
1/2
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
36179 if(box_active)
9386 {
9387 //do primitive text wrapping
9388 uint32_t i;
9389 for(i=0; i<temp.size(); i++)
9390 {
9391 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str())*box_text_scale;
9392
9393 if(length > box_r-box_l-16)
9394 {
9395 i = zc_max(i-1,0);
9396 break;
9397 }
9398 }
9399
9400 set_clip_rect(screen, box_l+8, box_t+1, box_r-8, box_b-1);
9401 if(box_text_scale == 1)
9402 textout_ex(screen, box_message_font, temp.substr(0,i).c_str(), box_l+8+box_x, box_t+(box_y+1)*box_message_height, gui_fg_color, gui_bg_color);
9403 else
9404 {
9405 int32_t length = text_length(box_message_font,temp.substr(0,i).c_str());
9406 BITMAP* tempbit = create_bitmap_ex(8, length, box_message_height);
9407 clear_bitmap(tempbit);
9408 textout_ex(tempbit, box_message_font, temp.substr(0,i).c_str(), 0, 0, gui_fg_color, gui_bg_color);
9409 stretch_blit(tempbit, screen, 0, 0, length, box_message_height/box_text_scale, box_l+8+box_x, box_t+(box_y+1)*box_message_height, length*box_text_scale, box_message_height);
9410 destroy_bitmap(tempbit);
9411 }
9412 set_clip_rect(screen, 0, 0, screen->w-1, screen->h-1);
9413 remainder = temp.substr(i,temp.size()-i);
9414 }
9415
9416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36179 times.
36179 if(box_log)
9417 {
9418 36179 sprintf(box_log_msg+box_msg_pos, "%s", msg);
9419 36179 }
9420
9421
1/2
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
36179 box_x += text_length(box_message_font, msg);
9422 36179 box_msg_pos+=(int32_t)strlen(msg);
9423
9424
2/4
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36179 times.
36179 if(remainder != "")
9425 {
9426 bool oldlog = box_log;
9427 box_log = false;
9428 box_eol();
9429 box_out(remainder.c_str());
9430 box_log = oldlog;
9431 }
9432
9433 // For web, always call update_hw_screen because it yields to the main thread,
9434 // which makes long running tasks like loading a quest not block the main thread,
9435 // which would make SFX sound awful on the title screen.
9436
3/6
✓ Branch 0 taken 36179 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36179 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36179 times.
36179 if (box_active || is_web())
9437 update_hw_screen(true);
9438 36179 }
9439
9440 /* calls box_out, and box_eol for newlines */
9441 void box_out_nl(const char *msg)
9442 {
9443 string line;
9444 istringstream reader(msg);
9445 while (getline(reader, line))
9446 {
9447 box_out(line.c_str());
9448 box_eol();
9449 }
9450 }
9451
9452 /* remembers the current x position */
9453 156 void box_save_x()
9454 {
9455
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9456 {
9457 box_store_x=box_x;
9458 }
9459
9460 156 box_store_pos=box_msg_pos;
9461 156 }
9462
9463 /* remembers the current x position */
9464 156 void box_load_x()
9465 {
9466
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 if(box_active)
9467 {
9468 box_x=box_store_x;
9469 }
9470
9471 156 box_msg_pos=box_store_pos;
9472 156 }
9473
9474 /* outputs text to the progress message */
9475 18309 void box_eol()
9476 {
9477
1/2
✓ Branch 0 taken 18309 times.
✗ Branch 1 not taken.
18309 if(box_active)
9478 {
9479 box_x = 0;
9480 box_y++;
9481
9482 if((box_y+2)*box_message_height >= box_h)
9483 {
9484 blit(screen, screen, box_l+8, box_t+(box_message_height*2), box_l+8, box_t+(box_message_height), box_w-16, box_y*box_message_height);
9485 rectfill(screen, box_l+8, box_t+box_y*box_message_height, box_l+box_w-8, box_t+(box_y+1)*box_message_height, gui_bg_color);
9486 box_y--;
9487 }
9488 }
9489
9490 18309 box_msg_pos = 0;
9491
9492
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18309 times.
18309 if(box_log)
9493 {
9494 18309 al_trace("%s", box_log_msg);
9495 18309 al_trace("\n");
9496 18309 memset(box_log_msg, 0, 480);
9497 18309 }
9498
9499
1/2
✓ Branch 0 taken 18309 times.
✗ Branch 1 not taken.
18309 if (box_active)
9500 update_hw_screen(true);
9501 18309 }
9502
9503 /* ends output of a progress message */
9504 691 void box_end(bool pause)
9505 {
9506
1/2
✓ Branch 0 taken 691 times.
✗ Branch 1 not taken.
691 if(box_active)
9507 {
9508 if(pause)
9509 {
9510 box_eol();
9511 box_pause();
9512 }
9513
9514 box_active = false;
9515 popup_zqdialog_end();
9516 }
9517 691 }
9518
9519 /* pauses box output */
9520 void box_pause()
9521 {
9522 if(box_active)
9523 {
9524 box_save_x();
9525 box_out("-- press a key --");
9526
9527 while(gui_mouse_b()) rest(1);
9528 while(!(keypressed() || gui_mouse_b())) rest(1);
9529 while(gui_mouse_b()) rest(1);
9530
9531 clear_keybuf();
9532 box_load_x();
9533 }
9534 }
9535
9536
9537 /*** The End ***/
9538